Icons and tabbing

Blitz3D Forums/Blitz3D Programming/Icons and tabbing

Jimmy(Posted 2014) [#1]
How do you adjust the icon in the window titlebar? And is there a way to make windows tabable in some way? I don't think they are?


videz(Posted 2014) [#2]
Hey Jimmy,

The only quick way I know which has been proven and always discussed here is by the use of Resource Hacker, desktop icon only

Otherwise, for a fool proof solution is to modify and add icon resources to the latest Blitz3D code available as source code.


videz(Posted 2014) [#3]
As for the tabable part, do you mean GUI stuff like WinBlitz3D or switching between windows?


Jimmy(Posted 2014) [#4]
Hey, ya exactly. When you press tab + shift it does not pop up in the list of apps?.

I suceeded to change the file icon using resource hacker now but it remains unchanged in the window unfortuntly.

Also I've never compiled C andthelike, is there aneasier way to change the icon? Diving into the binary or something like that?


videz(Posted 2014) [#5]
not sure why this is happening at your end but I can tab switch with my blitz3d window with a scene. Maybe something to do with the mouse pointer?

I don't know any method on replacing the windowed icon for a blitz3d app, unless you compile it from source which is now at your disposal.

Here's one I knew and used once but I'm not sure if its still compatible:

http://www.microangelo.us/icon-editor.asp


Rroff(Posted 2014) [#6]
Bit of a paste and run but this is one way to sort the window icon out:

Function icon()
	Local sStart
	Local sEnd
	Local sLen
	Local sCut
	Local temp
	Local hWnd
	Local modname$
	
	hWnd = SystemProperty("AppHWND")
	
	modname$ = GetCommandLine$()
	
	sStart = Instr(modname$,Chr$(34),1)
	sEnd = Instr(modname$,Chr$(34),sStart + 1)
	
	If (sStart = 0 Or sEnd = 0) Then
		conlog "*** Advisory: blank process name! WTF!"
		Return
	EndIf
	
	sCut = sStart
	
	For sCut = sStart To sEnd-1
		If ((Mid$(modname$,sCut,1)="\") Or (Mid$(modname$,sCut,1)="/")) Then
			sStart = sCut
		EndIf
	Next
	
	sStart = sStart + 1
	
	sLen = sEnd - sStart
	
	If (sLen = 0) Then
		conlog "*** Advisory: blank process name! WTF!"
		Return
	EndIf
	
	modname$ = Mid$(modname$,sStart,sLen)

	icon16 = ExtractIcon(hWnd,modname$,0)

	icon32 = icon16

	temp = SendMessage(hWnd,128,0,icon16)
	temp = SendMessage(hWnd,128,1,icon32)
	
	setCvar("sys_proc",modname$,CVAR_PERMA Or CVAR_READONLY)

End Function


Theres a bit of extra code in there from my own project and a few API calls I don't remember off the top of my head which system DLLs they are from for userlib purposes - will update later when I have a bit more time with the bare code/userlibs but it should be possible to work it out.

EDIT:

For completeness should also delete the icons in your program's exit routine (though they should be unloaded automatically in garbage collection):

	If (icon16) Then
		DeleteObject(icon16)
	EndIf

	If (icon32) Then
		DeleteObject(icon32)
	EndIf


icon16, etc. would have to be declared global.


videz(Posted 2014) [#7]
Hi Rroff. Looks like you got something going on here with bb code. May I ask where do you place the icon file name and how do you execute this function?

Thanks.


Rroff(Posted 2014) [#8]
After you've used resource hacker to push a custom icon into the exe this function then extracts that icon and replaces the default one in the window title (at run time only) - you could also load an external icon file but that is some slightly different code.

This function should be called as part of your initialisation code near the start of your program.

Also requires decls for gdi32, shell32 and user32 for the functions ExtractIcon, SendMessage, DeleteObject.


videz(Posted 2015) [#9]
Thanks Rroff but I'm getting a GetCommandLine$ not found and other stuff Error.. Looks like you got some external userlibs in here not posted for clarity.

I seem to have some of those functions in blitz user libs but its declared as api_GetCommandLine()...


videz(Posted 2015) [#10]
Ok not to overshadow your cool solution Rroff (which I still need to test out :)) but guys I now figured out another way to solve this.. :)

Since you are setting up a windowed game/app showing title and icon titlebar, I would consider using WinBlitz3D, a very nifty Windows GUI userlib. I'm currently testing this out and I remember there's a set of function that is related to your window icon problem.

1) Use Resource Hacker to change the icon resource..

2) Download and install WinBlitz3d 1.1. I posted this resource on the beginners 101 list here.

3) Add this to the init section of your game/app

Include "WB3DStyles.bb"

Global window = WB3D_InitializeGUI(SystemProperty("AppHwnd"),0,0,0,0)

;Add icon using bmp icon strip
icons = WB3D_LoadIconStrip("icons.bmp",16,0)
WB3D_SetWindowIcon(window,icons,0)

;AppTitle will be ignored, use this instead
WB3D_SetGadgetText(window,"My Game")


Icon Option #2 No external icon files needed and using standard .ico or icon library files. Replace code lines 2 and 3 of the above with this
 
;Match the filename below with your final Game Exe filename or use icon.ico/icon.dll library for icon external file
icon=ExtractIconA(window,"YourGame.exe",0)
SetClassLongA(window,-14,icon)


but need to do these items...

Inside userlibs folder

Create or add file user32.decls
.lib "user32.dll"
SetClassLongA%(hWnd%,nIndex%,Value%):"SetClassLongA"


Create or add file shell32.decls
.lib "shell32.dll"
ExtractIconA%(hWnd%,File$,Index%):"ExtractIconA"


The WB3D method icon set is not embedded but it also works ok.

One thing to note: I have noticed when tampering with titlebar objects, the AppTitle command will be ignored. So using WB3D SetGadgetText is one straight solution in doing these changes..

You could also use the **No DLL version** of WinBlitz3d which I will try to find the link again and update here..




_PJ_(Posted 2015) [#11]
"GetCommandLine$()"
I think the generic Blitz command CommandLine$() returns exactly the same? If not, then it would be:
Chr(34)+SystemProperty("AppDir")+[executablefilename]+Chr(34)+CommandLine$()


(I'll have to check this at home when I can access B3D)


Rroff(Posted 2015) [#12]
Mine is pretty much the same as option 2 btw I'm just making sure the user hasn't renamed the exe and/or allowing for multiple different exe names without hardcoding it.

EDIT: As for getcommandline$ its 5+ years since I wrote that code but IIRC its one of the most reliable ways to get the actual executable name as it is on disc to extract the icon without any hardcoding or possible issues with things being renamed either on disc or in memory.


Jimmy(Posted 2015) [#13]
That titlebar is stubborn everything else changes allright.
Tab works, icon is there, but the icon in the titlebar stucks.

This is what I think now is the right track. As it is now it changes the tab allright.

But the actual code that I *think* SHOULD be done instead to be able to change icons in *both places* are marked out.
LOADIMAGE win API and It´s just a few lines but I got the API parameters abit wrong, working on it.

; Version 1 (working but changes only one icon, the larger one)

seticon("app.exe")
WaitKey

Function SetIcon(iconfile$, iconindex=0, hWnd=0)
GCL_HICON = -14
GCL_HICONSM = -34 ; does not work in B3D at elast, does the same as HICON

hWnd = api_GetActiveWindow()
hIcon = api_ExtractIcon (hWnd, iconfile$, iconindex)
api_SetClassLong(hWnd, GCL_HICON, hIcon)

End Function


This one one would love to have working, windows API is complex too me right now so somethings is missing

; Version 2 (Will change both icons when working and in a more modern "correct" fashion)
seticon("app.exe")
WaitKey

Function SetIcon(iconfile$, iconindex=0, hWnd=0)
GCL_HICON = -14
GCL_HICONSM = -34
WM_SETICON       = $80 
LR_LOADFROMFILE  = $10
ICON_SMALL       = 0   ; 16x16
ICON_BIG         = 1   ; 32x32
IMAGE_ICON       = 1
LR_DEFAULTSIZE 	 = $40
LR_LOADFROMFILE	 = $10
SM_CXICON  	 	 = 11
SM_CYICON 		 = 12
SM_CXSMICON 	 = 49
SM_CYSMICON 	 = 50
IMAGE_ICON= 1
IMAGE_BITMAP	 = 0

hWnd = api_GetActiveWindow()
hIcon = api_LoadImage(Api_GetModuleHandle_Null(0), iconfile$,MAKE_ICON,api_GetSystemMetrics(SM_CXICON),api_GetSystemMetrics(SM_CYICON),0)
If hIcon Then api_SendMessage(hWnd, WM_SETICON, ICON_BIG, hIcon)
hIcon = api_LoadImage(Api_GetModuleHandle_Null(0), iconfile$,MAKE_ICON, api_GetSystemMetrics(SM_CXSMICON), api_GetSystemMetrics(SM_CYSMICON),0)
If hIcon Then api_SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIcon)

End Function



videz(Posted 2015) [#14]
Hey Jimmy, glad you sorted this out. I already have mine working since I'm also using WinBlitz3D but anyway cool solution you got here.


Jimmy(Posted 2015) [#15]
Haha maybe I´m close maybe I´m not but GOD!! to much energy and time and lack of sleep and health already has gone into an ICON ;)


videz(Posted 2015) [#16]
lol yeah. although the winblitz3d method needs some dlls and includes, its the quickest one I got so far working on my end :) just took me an hour once I remembered that wb3d already got the functions to add this to an app.

cheers.


Jimmy(Posted 2015) [#17]
;) actually I have a simple dll solution from here already http://www.blitzforum.de/forum/viewtopic.php?t=14671
it´s about 40k compressed I think, Seticon"blah" and then you´re done.

But... ya I went for the adventure to try find a more elegant solution for myself, the hard way.

But suddenly I think this dll seem like a really really reasonable solution.


videz(Posted 2015) [#18]
oh nice! would check that out too


Jimmy(Posted 2015) [#19]
You like that huh? How about something I just succeeded with ! ;) no dll zip zero nada.

And I made it minimalistic without xobstants and changes. Got tired of them haha.

Here you go. Proffesional look on your apps. 4 lines.

[Code]
; Change icon the correct way EVERYWHERE inside an app
hwnd = SystemProperty( "AppHWND" ) : icon=api_ExtractIcon(hwnd,"some-exe-or-icon.ico",0)
api_SendMessage(hwnd, $80 , 0, icon) : api_SendMessage(hwnd, $80 , 1, icon)

WaitKey

; file user32.decls ADD
; api_SendMessage% (hwnd%, wMsg%, wParam%, lParam%) : "SendMessageA"

; file Shell32.decls ADD
; api_ExtractIcon% ( hWnd%, File$, Index% ) : "ExtractIconA"
[/code]


videz(Posted 2015) [#20]
hey thanks Jimmy. I'm trying this out on B3D/B+ but I can't seem to get it to work and I keep getting MAV..


Jimmy(Posted 2015) [#21]
I'm using Blitz3D in Windows7 64bit
Be sure the api_sendmessage is letter by letter perfect don't rely on other sources. That was the culprit for me.

They ended in Iparam*
it should end in Iparam%

Try that and tell how that went


videz(Posted 2015) [#22]
Yes copied exactly and I put in icon name on my executable after I added my resource hacker icon. I'm also using Win7 64 and Vista.

I'm trying it on B+, any difference in code? I assume it will work just the same


Jimmy(Posted 2015) [#23]
That's odd, ya it should work equally well there for all I know.

you could try use the internal equvivalent I guess if just maybe there are some strange collisions in how it works internally.

Does Blitzplus have pointer types that B3D does not have? I admit all that is abit stretchy but I have no other idea why it might not work.

It should work, I tried with clean decls libs now and just that code I gave and it works like charm in blitz3d 1.106 and latest 1.108


Jimmy(Posted 2015) [#24]
; get hwnd in blitzplus (tested and works fine, blitz3d and blitz+ needs two diff approaches to get hwnd)
Hwnd=QueryObject(createwindow("appname",100,100,400,300,0,5),1)


Jimmy(Posted 2015) [#25]
To round up I put both solutions here as there have been much confusion and alot of effort to get these findings.

Both are tried and works with Blitz3D and BlitzPlus respectively.

Blitz3D :

; Change icon the correct way EVERYWHERE inside an app

hwnd = SystemProperty( "AppHWND" ) : icon=api_ExtractIcon(hwnd,"myapp.exe",0)
api_SendMessage(hwnd, $80 , 0, icon) : api_SendMessage(hwnd, $80 , 1, icon)

WaitKey

; file user32.decls ADD
; api_SendMessage% (hwnd%, wMsg%, wParam%, lParam%) : "SendMessageA"

; file Shell32.decls ADD
; api_ExtractIcon% ( hWnd%, File$, Index% ) : "ExtractIconA"


BlitzPlus

; Change icon the correct way EVERYWHERE inside an app

Hwnd=QueryObject(createwindow("appname",100,100,400,300,0,5),1) 
icon=api_ExtractIcon(hwnd,"myapp.exe",0)
api_SendMessage(hwnd, $80 , 0, icon) : api_SendMessage(hwnd, $80 , 1, icon)

WaitKey

; file user32.decls ADD
; api_SendMessage% (hwnd%, wMsg%, wParam%, lParam%) : "SendMessageA"

; file Shell32.decls ADD
; api_ExtractIcon% ( hWnd%, File$, Index% ) : "ExtractIconA"


Blitzplus running example

window=CreateWindow( "Test",ClientWidth(Desktop())/2-96,ClientHeight(Desktop())/2-96,192,192,0,7)
appname$="appname" : AppTitle appname$
hwnd=QueryObject(window,1)
icon=api_ExtractIcon(hwnd,"myapp.exe",0)
api_SendMessage(hwnd, $80 , 0, icon) : api_SendMessage(hwnd, $80 , 1, icon)

width=ClientWidth(window) : height=ClientHeight(window)
canvas=CreateCanvas( 0,0,width,height,window )
SetGadgetLayout canvas,1,1,1,1
SetBuffer CanvasBuffer(canvas)

While WaitEvent(10)<>$803
	mx=MouseX()-width/2: my=MouseY()-height/2
	Cls
	CopyRect mx,my,width,height,0,0,DesktopBuffer()
	FlipCanvas canvas
Wend

End



videz(Posted 2015) [#26]
Oh yeah. sorry Jimmy. I got confused and forgot the QueryObject thing.

Problem solved and works great! awesome simple solution :D

One thing just missing is Rroff's getcommandline and it will be perfect..


Jimmy(Posted 2015) [#27]
Glad to hear it worked out!


videz(Posted 2015) [#28]
yeah Jimmy, hey you could also post this to code archives for others to see and benefit from :-)

cool work


Jimmy(Posted 2015) [#29]
I put some links here :)

Customizing your app icon

BlitzPlus version
http://www.blitzbasic.com/codearcs/codearcs.php?code=3173

Blitz3D version
http://www.blitzbasic.com/codearcs/codearcs.php?code=3174


videz(Posted 2015) [#30]
noice! :O


Rick Nasher(Posted 2015) [#31]
Getting "ERROR: Internal error" on the Blitz3d link..


RGR(Posted 2015) [#32]
The easiest way to customize your AppIcon in Blitz3D ...

Use an IconEditor and create your 32x32 Icon ... 8-Bit Colortable ... IconFile must be 2238 Bytes long after saving ...


Write a little Program which includes this Subroutine (works for the most important last Blitz3D Versions):

.PatchIcon
	ToPatchFile$="runtime.dll"
	Ok=0
	If FileSize(ToPatchFile$)=1290240 Then Ab=$12b134 :Ok=1
	If FileSize(ToPatchFile$)=1314816 Then Ab=$130134 :Ok=1
	If FileSize(ToPatchFile$)=1318912 Then Ab=$131134 :Ok=1
	If FileSize(ToPatchFile$)=1323008 Then Ab=$132134 :Ok=1
	Bis=Ab+2219
	
	If Ok=0
		RuntimeError "Wrong runtime.dll version"
		End
	EndIf
	If UsedIcon$<>""
		x=FileSize(UsedIcon)
		If x<>2238
			Print "Wrong Format - unable to Patch"
			Print "Use 32x32 256color icon"
			Return
		Else
			Print "Icon size "+x+" ok"
		EndIf
		bank=CreateBank(x)
		filein=ReadFile(UsedIcon)
		If filein<>0
			ReadBytes bank,filein,0,x
			CloseFile filein
			Print "Iconfile loaded"
		Else
			Print "Iconfile load failed"
		EndIf
		
		fil=OpenFile(ToPatchFile)
		If fil<>0
			For i=Bis To Ab Step -1
				x=x-1
				SeekFile(fil,i)
				WriteByte fil,PeekByte(bank,x)
			Next
			CloseFile fil
			Print "runtime.dll successfully patched"
		Else
			Print "runtime.dll could not be opened"
			Print "Possible Error:"
			Print "runtime.dll is used by this program"
			Print "Create and run PatchIcon.exe"
		EndIf
		FreeBank bank
		Return
	EndIf
	Print "Nothing done"
Return


Use a Filerequester to get the Path and Filename of your Icon File
Or load the Path and Filename from an inifile ...

You must create an exe of this Patchfile ... because you patch the runtime.dll which must not be opened ... and it is open while the Temp.exe (your patcher) is running from the Blitz IDE...
Make a Copy of the runtime.dll before you do anything. Because the old icon will be overwritten and every following compiled exe will have your new Icon ...

I would have provided a complete running program - but the one I have does not work for you ... it's part of a complex preprocessing precompiler system which does patching automatic while creating the final exe ...
I use the PureBasic IDE to write Blitz3D-Code in PureBasic Style which gets converted to Blitz3D-Code with a Preprocessor ...
If you ask why ... I have autocomplete on all Functions which syntax check, parameters showing at the bottom line, autocomplete on all variables, arrays, types, 4000 custom functions highlighted with parameters showing, included automatic (no includefiles), etc... ;-)


Jimmy(Posted 2015) [#33]
I noticed one version is gone? what´s up with the archives? My name is still there but there´s an error? BlitzSupport? Is it deleted by misstake?


Jimmy(Posted 2015) [#34]
RGR, that´s a nice patch I think I will try that aswell. Though sometimes you really want an icon to be set runtime for weird things such as say modes or convey some info, I wonder if Windows is "up for it" to animate the icon even. It would certainly be an odd thing to do though. But the option is nice.


Jimmy(Posted 2015) [#35]
I guess there was an upload error or something. I uploaded it again for anyone who wants it.

Customizing your app icon

BlitzPlus version
http://www.blitzbasic.com/codearcs/codearcs.php?code=3173

Blitz3D version
http://www.blitzbasic.com/codearcs/codearcs.php?code=3177


videz(Posted 2015) [#36]
Thanks for the update Jimmy and RGR that looks good to try..

BUT what I would be interested now in is how do you PROPERLY add the icon resouce like bbexe.ico and a titlebar icon in the BP/B3D sources. No hacks, just straight up icon resource compilation.

For Blitz3D the destkop icon is already in there in the runtime.dll project. I'm not sure with BPlus, it's showing none or default program win icon.

VC6 is too old for me (I started VS2008) and I can't seem to find docs or articles for it (at the moment)

I now think this is the practical way to do it with B3D/BP opensourced.


Rroff(Posted 2015) [#37]
The reason the window used by b3d compiled programs has a default icon is that the window class structure used to register the window class before CreateWindowEx is called lacks entries for hIcon and/or hIconSm.

There is probably no way to fix the compiled executables short of significant hacking to replace the structure other than recompiling the b3d source itself.

EDIT: Oh yeah api_getcommandline is probably the same function - I just manually added the api call to it instead of using one of the pre-built kernel32 decls (I tend to manually add/remove stuff as needed to narrow the scope of where potential errors might be originating from).

.lib "kernel32.dll"
GetCommandLine$ () : "GetCommandLineA"


videz(Posted 2015) [#38]
Hey thanks for the info Rroff! So I get it now that this has something to do with lacking of icon entries and the source is now available.

Yes, I also did mention that it is now practical to just recompile the source since it is now available. Do you have any idea how to add the icon title in the resource? and also add a default icon to BlitzPlus

Noted on the api_getcommandline, I will try to add this later.


Rroff(Posted 2015) [#39]
You can't add the title bar icon to the resource file AFAIK (I'm a bit rusty on that) the runtime wndclass structure used to register the window class needs a couple of additional lines so that when CreateWindowEx is called the specified icon is used.


videz(Posted 2015) [#40]
It is definitely possible. I have easily done this with VS2010 and VS2008 projects. I'm not sure about the format and procedure workspace/solution which is currently and apparently in VC6. :/

It's also a bit weird why the authors at BRL did not upgrade or at least have them update with the latest Visual Studio for their own use. But hey its a big thanks this went open source.

I'm not complaining, just a minor thing and wanted to scratch this itch.


Rroff(Posted 2015) [#41]
You can add an icon into the executable via resource editing and later use it as the titlebar icon via the window class structure but I'm not sure you can use the resources to specifically define an icon as the window/title icon without any extra code.


videz(Posted 2015) [#42]
Ok I guess we could circle back on that part. Anyways, I revised your code and came up with this sample routine to go with Jimmy's code to replace the appname issue and can now deal with renaming the file itself:

Function GetExeName$()

	modname$ = GetCommandLine$()
	
	sStart = Instr(modname$,Chr$(34),1)
	sEnd = Instr(modname$,Chr$(34),sStart + 1)
	
	If (sStart = 0 Or sEnd = 0) Then
		;Show console or error log here
		Return
	EndIf
	
	sCut = sStart

	For sCut = sStart To sEnd-1
		If ((Mid$(modname$,sCut,1)="\") Or (Mid$(modname$,sCut,1)="/")) Then
			sStart = sCut
		EndIf
	Next
	
	sStart = sStart + 1
	
	sLen = sEnd - sStart
	
	If (sLen = 0) Then
		;Show console or error log here
		Return
	EndIf
	
	modname$ = Mid$(modname$,sStart,sLen)

	Return modname$

End Function

Graphics 800,600,0,2	

Text 1,1,GetExeName()

WaitKey



videz(Posted 2015) [#43]
Already posted the addendum here:

http://www.blitzbasic.com/codearcs/codearcs.php?code=3177#comments


Jimmy(Posted 2015) [#44]
ahhh it check now its own filename. Clever stuff. Great work Videz and Rroff too, very nice.. I would love to look into that later, would it be okay to update the codearchives later perhaps and make it general if it all works out?


videz(Posted 2015) [#45]
yeah Jimmy, of course. I already tested this before posting that addendum

now this can be a final solution :)


Jimmy(Posted 2015) [#46]
Got it to work, I´ve never used BlitzPlus very much and when I should try change the actual exe icon resource in it it seems that it has no icon to replace? The exe Plus spits out is nowhere like the Blitz3D? Which has a default icon to replace. What have I missed? I´m abit peckish to try learn Blitzplus.


videz(Posted 2015) [#47]
Nice. With BlitzPlus, there's really no default icon included in the compiled or runtime dll. I learned a trick somewhere here that you need to create or hack it using ResourceHacker..

Open exe in reshacker
Go to Action->add new resource
Select the desired icon file (.ico)
Type ICON as Resource Name in all caps (reshacker auto caps it)
Save File Exe

Done :-)