|
Cyrilix wrote: I believe the above is known as static linking with DLLs
or dynamic linking, early binding
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
I stand corrected.
|
|
|
|
|
I never said I was correct!
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
Hi, Guys,
Great suggestions! I will take all of your points.
Thanks a lot!
Skywalker2008/Stanley Hu
|
|
|
|
|
I have a resource dll into which I placed about 12 32-bit (with alpha) bitmaps. I've been trying to load them from the dll WITHOUT using the dll header but can't figure it out. Can anyone give me some advice/examples of how to do this?
|
|
|
|
|
Maybe the LoadImage() API? I'm not positive ARGB bitmaps are supported - it may require the
LR_CREATEDIBSECTION flag.
GDI+ has a Bitmap class constructor that takes an HINSTANCE and a resource name as well.
LoadLibrary() will get you the HINSTANCE of the resource DLL.
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
Loading the bitmap onto the screen is not the problem... The ARGB's show up just fine with the LoadImage function. The problem is getting the bitmap OUT of the dll. I load the dll but can't get a handle to the bitmap inside. I'm trying to avoid using the header file if I can... For instance, when loading icons from a dll, you can use the ExtractIcon function and it's pretty simple. I'm looking for a way to load a bitmap in this manner.
|
|
|
|
|
So you don't know the name (or ID) of the bitmap you want to extract?
If so, you can enumerate all the bitmap names in the DLL with
EnumResourceNames(hDllModule, RT_BITMAP, ...).
I'm not sure how you determine which one you want...by index I suppose, although I'm not sure
if the order the names are sent to the callback are in a defined order
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
I know the name of them... But when I try to use FindResource or LoadImage (or anything else that gets a handle) I get an error saying that "the specified resource was not found in the image file"
|
|
|
|
|
Ok, didn't you say you had no problem loading them and displaying them with LoadImage()?
What kind of handle are you trying to get?
You should have a valid HMODULE/HINSTANCE for the DLL to start with, or else it will never work.
You can get that by loading the DLL with LoadLibrary();
Then you need a valid name - if it's an integer ID then use the MAKEINTRESOURCE macro to convert the ID to a name "string".
HMODULE hResDLLModule = ::LoadLibrary(_T("c:\\path\myresdll.dll"));
if (hResDLLModule)
{
HBITMAP hBitmap = (HBITMAP)::LoadImage(hResDLLModule, MAKEINTRESOURCE(IDB_BITMAP), ...);
...
::FreeLibrary(hResDLLModule);
}
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
Right... see, I can open the dll using either LoadLibrary or AfxLoadLibrary... that part works fine. I just can't get a handle to the bitmap in the dll. I know the string name of it, but the int isn't defined in the project. So I tried LoadImage(instance, _T("IDB_BITMAP1"),...) but didn't get it. When I try FindResource with that method, it doesn't find the bitmap either.
I got it to work by including the header file from the dll project in my current project. But I don't want to rely on that in case I want to change the images later by just swapping another dll.
|
|
|
|
|
Gotcha. Only icons can be loaded by an index, AFAIK.
By "name" I mean the ID of a resource - all resources have a name - it's a string. The use of
integer IDs is usually (if not always ) easier but to use an integer it has to be cast to
a string pointer (which is what MAKEINTRESOURCE is for). I'm using "name" to mean the ID of the
resource.
You indicated again you don't want to have to know the name of the resource when you load it.
The only way you can do that is enumerate all the bitmaps in the DLL and pick the bitmap you want
somehow. EnumResourceNames() will enumerate all the bitmap names in the DLL - pick the name you
want and load the bitmap with LoadImage() (or whatever method) using that name
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
See, I've never done this before (obviously). I was thinking that the string name of the resource is stored in the dll too, so you could get a handle that way. I basically want to be able to load from xdll a bitmap named IDB_SOMETHING and have the ability to replace that xdll with a different dll that has different bitmaps with the same name.
|
|
|
|
|
I'm following you now
I've never used strings to name a resource so I was wondering how it's done LOL.
In the resource editor, if you put the ID in quotes it will be a string name. In that case you
should be able to pass the name like you did in your sample: _T("IDB_BITMAP")
Make sure that name isn't a #define in the resource header file (resource.h) or it will be
interpreted as the integer it's defined to
To be able to swap DLLs, your new DLLs will need to name the bitmaps the same.
Sorry for all the confusion!
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
lol... will that work??? sounds too easy to be right.... but i guess i'll find out.
|
|
|
|
|
sstainba wrote: will that work???
I tried it first LOL - like I said, I've always just used integers!
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
sstainba wrote: See, I've never done this before
That's why I'm trying to confuse you more! j/k
In the resource editor, when you add a bitmap and set its ID property to something like
IDB_BITMAP1 (or when the editor defines it for you), instead of using IDB_BITMAP1 as-is, it
adds a "#define IDB_BITMAP1 101" entry to resource.h. IDB_BITMAP1 is now a macro, not a string.
So if you try to load a resource using _T("IDB_BITMAP1") as the name, the resource isn't there
because the editor "helped" you by changing IDB_BITMAP1 to an integer.
Therefore, to use string names, when you add the resource, hit F4 to bring up the properties
page for the bitmap and edit the "ID" property to a string in double quotes.
I hope that is more understandable
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
Ok... that took me a step in the right direction. At least now FindResource is returning a non-NULL handle. I changed the name to include the quotes and it seems to be ok... But I still can't load it onto a button.
HINSTANCE mh = ::AfxLoadLibrary(_T("icons.dll"));
HINSTANCE mb = ::AfxFindResourceHandle(_T("IDB_BITMAP36"), RT_BITMAP);
Both of these return non-NULL handles... but I can't get it to work with LoadImage or LoadBitmap or just casting the mb as an HBITMAP.
I'm trying to set a bitmap field on a button... CButton::SetBitmap(HBITMAP)
Should I maybe use LoadLibrary and FindResource (non-Afx) ? I can't see that it would make a difference... but who knows.
|
|
|
|
|
I think you only need to use FindResource()/AfxFindResourceHandle for obtaining handles to binary
or custom resource types.
For bitmaps, you should use LoadImage(); That should work....are you sure you have the BS_BITMAP
style set on the button (if it's a button resource on a dialog, use F4 to get properties and set
the Bitmap property to true)?
I just tested this and it worked (note that I used ::GetModuleHandle(0) since the bitmap resource
is in my exe file):
HBITMAP hbitmap = (HBITMAP)::LoadImage(::GetModuleHandle(0), _T("MYBITMAP"), IMAGE_BITMAP, 0, 0, 0);
m_BitmapButton.SetBitmap(hbitmap);
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
Yeah, the button is set correctly. I can load it just fine as long as I include the header and use the int name. I just tried what you've got up there and it's a no go. LoadImage isn't returning a valid handle. Maybe it's because it is in a dll file and not the exe?
|
|
|
|
|
sstainba wrote: LoadImage isn't returning a valid handle.
Is LoadImage() returning NULL? If so, make sure IDB_BITMAP36 isn't defined anywhere else in the
project (most likely resource.h). A "Find in Files..." search in the DLL project for
"IDB_BITMAP36" should only find it once - in the .RC file.
If the name isn't the problem, and LoadImage() is returning NULL, then maybe check the error code
something like this...
HINSTANCE mh = ::AfxLoadLibrary(_T("icons.dll"));
HBITMAP hbitmap = (HBITMAP)::LoadImage(mh, _T("IDB_BITMAP36"), IMAGE_BITMAP, 0, 0, 0);
if (hbitmap)
{
m_BitmapButton.SetBitmap(hbitmap);
}
else
{
DWORD errcode = ::GetLastError();
}
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
sstainba wrote: I can load it just fine as long as I include the header and use the int name
I read that and apparently ignored it If that works then it's definitely the name -
Open the resource.h file in the DLL project and remove any #define entry for IDB_BITMAP36.
Since you're using strings, it may be helpful to use more descriptive names - there's no reason to
use the naming conventions that are assigned by the Visual Studio editing environment.
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
YAY!!!!! It worked. You rock. Hahaha... I tried asking this questiong on CodeGuru and this one guy was acting like I was an idiot for even thinking such a thing could be done. He said that the resource name wasn't stored in the dll file (WTF?). Anyway, thanks a lot!
PS. I don't suppose you know how to get a CToolTipCtrl to work do you? I followed the MSDN but it never shows up...
|
|
|
|
|
sstainba wrote: I tried asking this questiong on CodeGuru and this one guy was acting like I was an idiot for even thinking such a thing could be done.
Yeah - I was pretty much called stupid for asking a question on the Microsoft boards the
first time I went there. Geez, if you're tired of answering "stupid" questions then don't answer!
I personally believe the only stupid question is one that isn't asked (I don't know where I heard
that....maybe read it on a Starbucks cup or something )
sstainba wrote: He said that the resource name wasn't stored in the dll file (WTF?).
I wonder how he thought resources were located
sstainba wrote: PS. I don't suppose you know how to get a CToolTipCtrl to work do you? I followed the MSDN but it never shows up...
For a dialog window, right? I'll steal an example right from the MFC sample code:
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
...
EnableToolTips(TRUE);
...
afx_msg BOOL OnToolTipNotify(UINT id, NMHDR * pNotifyStruct, LRESULT * result);
...
BOOL CMyDlg::OnToolTipNotify(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
{
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
CStringA strTipText;
UINT nID = pNMHDR->idFrom;
if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
{
nID = ::GetDlgCtrlID((HWND)nID);
}
if (nID != 0)
strTipText.Format("Control ID = %d", nID);
if (pNMHDR->code == TTN_NEEDTEXTA)
strncpy(pTTTA->szText, strTipText, sizeof(pTTTA->szText));
else
::MultiByteToWideChar( CP_ACP , 0, strTipText, -1, pTTTW->szText, sizeof(pTTTW->szText) );
*pResult = 0;
return TRUE;
}
Note that this just shows a normal tooltip with text "Control ID = xxxx". You'd probably want to
map the control ID to a meaningful string.
Cheers
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|
I forgot to mention....
if you choose to implement tooltips like that sample code, the strings you use can be loaded
from a stringtable resource, and the stringtable can be in your resource DLL.
The TOOLTIPTEXT structs have a hinst member to specify the HINSTANCE of the DLL.
If you choose to use stringtable resources for the strings, then lpszText should be set to the
ID of the string resource and the hinst member set to the instance of the module (EXE or DLL)
that contains the resource, something like:
// get string 32777 from this EXE's resources
pTTTW->hinst = ::GetModuleHandle(0);
pTTTW->lpszText = (LPWSTR)32777;
Mark
"I'm the Dude. So that's what you call me. You know, that or, uh, His Dudeness, or uh, Duder, or El Duderino if you're not into the whole brevity thing." The Big Lebowski
|
|
|
|
|