お世話になります。
下記のコードをWindows2000で動作させると、Uxtheme.dllが見つかりませんというエラ
ーが出ます。
当然と言えば当然なのですが、このようなアプリケーションをWindows2000に対応させる
ためにはどのようにコードしたら良いのでしょうか?
#include <windows.h>
#include <Uxtheme.h>
#pragma comment(lib, uxtheme.lib)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine,
int nCmdShow)
{
HINSTANCE hLib = LoadLibrary(Luxtheme.DLL);
if (hLib || 0)
{
HTHEME hTheme;
hTheme = OpenThemeData(0,Lprogress);
if (hTheme == NULL)
{
MessageBox(0,Lテーマ無理ッス!,L",MB_OK);
} else {
MessageBox(0,Lテーマ行けます!,L",MB_OK);
}
} else {
MessageBox(0,Lテーマ無理ッス!,L",MB_OK);
}
FreeLibrary(hLib);
return 0;
}
> #pragma comment(lib, uxtheme.lib)
この行を削れば起動時のエラーを回避できます。
この場合はLoadLibrary()とGetProcAddress()関数で利用したい関数群を
すべて取得します。そうすれば Uxtheme.dll がないOSでも起動して
独自のエラー処理が行えます。
なお Uxtheme.dll がない場合は通常のテーマなしで起動を
続けるようにすれば良いでしょう。
あるいは uxtheme.dll をプログラムと一緒に配布するとか。
#pragma消すとOpenThemeData関数の定義がないってリンクエラーになるはずです。
GetProcAddress関数を使うように変更が必要でしょう。
それと、FreeLibraryはLoadLibraryが成功したときのみだけ呼び出したほうが良いですね。
具体的なコードは
http://mspace.sakuraweb.com/comp/prog/dll.html
を参考にしてみてください。
リンカの設定で uxtheme.dll を遅延読み込み(/DELAYLOAD)に
指定する方法もあります。
皆さんありがとうございます。
リンカ→入力:DLLの遅延読み込み(/DELAYLOAD)
すごく便利ですね。
コンパイラはVC++でのみ利用可能なのでしょうね。
重宝しそうです。
リンカによる DLL の遅延読み込み
http://msdn.microsoft.com/ja-jp/library/151kt790(VS.80).aspx
DLL の遅延読み込みの制約
http://msdn.microsoft.com/ja-jp/library/yx1x886y(VS.80).aspx
コードによる遅延読み込みの場合、関数を新規作成(OpenThemeData2)しましたが、
これを(OpenThemeData)として扱う方法ってあるのでしょうか?
もしかして、Uxtheme.hから作らないといけないのですかね…
#include <windows.h>
#include <Uxtheme.h>
//#pragma comment(lib, uxtheme.lib)
typedef HANDLE (WINAPI *LPFNOPENTHEMEDATA)( HWND, LPCWSTR );
HTHEME OpenThemeData2( HWND hWnd, LPCWSTR pszClassList)
{
HANDLE hTheme = NULL;
HMODULE hLibrary = ::LoadLibrary( Luxtheme.dll );
if ( hLibrary != NULL )
{
LPFNOPENTHEMEDATA lpfnOpenThemeData;
lpfnOpenThemeData = (LPFNOPENTHEMEDATA)::GetProcAddress(
hLibrary, OpenThemeData );
if ( lpfnOpenThemeData != NULL )
hTheme = lpfnOpenThemeData( hWnd, pszClassList);
::FreeLibrary( hLibrary );
}
return hTheme;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine,
int nCmdShow)
{
//HINSTANCE hLib = LoadLibrary(Luxtheme.DLL);
//if (hLib || 0)
//{
HTHEME hTheme;
hTheme = OpenThemeData2(0,Ledit);
if (hTheme == NULL)
{
MessageBox(0,Lテーマ無理ッス!,L",MB_OK);
} else {
MessageBox(0,Lテーマ行けます!,L",MB_OK);
}
// FreeLibrary(hLib);
//} else {
// MessageBox(0,Lテーマ無理ッス! no DLL,L",MB_OK);
//}
return 0;
}
とりあえず思いついた方法ですが、
クラス化して扱ってしまおうかと検討しています。
ライブラリのチェックも一発ですし。
皆さんはどうしているんですか?
もう少しネットも調べてみますが、
c++初心者でして、ネットの情報うまいこと吸いだせません;;
class Ctheme
{
public:
Ctheme();
~Ctheme();
void Create(); //初期化
HTHEME OpenThemeData( HWND hWnd, LPCWSTR pszClassList);
};
/DELAYLOADはやったことがないので、動的にdllをロードする場合
// ThemeFunction.h
class CThemeFunction
{
private:
static CThemeFunction m_Instance;
HMODULE m_hModule;
typedef HANDLE (WINAPI *LPFNOPENTHEMEDATA)(HWND, LPCWSTR);
LPFNOPENTHEMEDATA m_lpfnOpenThemeData;
typedef HRESULT (WINAPI* LPFNCLOSETHEMEDATA)(HANDLE);
LPFNCLOSETHEMEDATA m_lpfnCloseThemeData;
CThemeFunction();
virtual ~CThemeFunction();
bool IsUsable() const { return (this->m_hModule != NULL); }
public:
static HANDLE OpenThemeData(HWND hWnd, LPCWSTR pszClassList);
static HRESULT CloseThemeData(HANDLE hTheme);
};
// ThemeFunction.cpp
CThemeFunction CThemeFunction::m_Instance;
CThemeFunction::CThemeFunction()
: m_hModule(NULL)
, m_lpfnOpenThemeData()
, m_lpfnCloseThemeData()
{
this->m_hModule = ::LoadLibrary(_T(uxTheme.dll));
if (this->m_hModule != NULL)
{
this->m_lpfnOpenThemeData = reinterpret_cast<LPFNOPENTHEMEDATA>
(::GetProcAddress(this->m_hModule, OpenThemeData));
this->m_lpfnCloseThemeData = reinterpret_cast<LPFNCLOSETHEMEDATA>
(::GetProcAddress(this->m_hModule, CloseThemeData));
}
}
CThemeFunction::~CThemeFunction()
{
if (this->IsUsable())
{
::FreeLibrary(this->m_hModule);
}
}
HANDLE CThemeFunction::OpenThemeData(HWND hWnd, LPCWSTR pszClassList)
{
HANDLE hTheme = NULL;
if (m_Instance.IsUsable())
{
if (m_Instance.m_lpfnOpenThemeData != NULL)
{
hTheme = (*m_Instance.m_lpfnOpenThemeData)(hWnd, pszClassList);
}
}
return hTheme;
}
HRESULT CThemeFunction::CloseThemeData(HANDLE hTheme)
{
HRESULT hr = S_OK;
if (m_Instance.IsUsable())
{
if (m_Instance.m_lpfnCloseThemeData != NULL)
{
hr = (*m_Instance.m_lpfnCloseThemeData)(hTheme);
}
}
return hr;
}
という感じでしょうか。
せっかくなのでDELAYLOADでやる例も載せておきます。
//Theme.h
#ifndef THEME_H_
#define THEME_H_
#include <windows.h>
#include <uxtheme.h>
#include <tmschema.h>
class Theme {
public:
Theme();
virtual ~Theme();
bool Open(HWND hWnd, LPCWSTR pszClassList);
void Close();
bool DrawBackground(HDC hDC, int iPartId, int iStateId, const RECT& rect,
const RECT* pClipRect = NULL) const;
private:
Theme(const Theme&);
Theme& operator=(const Theme&);
static bool IsThemingSupported();
static bool themingSupported;
HTHEME hTheme;
};
#endif
//Theme.cpp
#include theme.h
#pragma comment(lib, uxtheme.lib)
bool Theme::themingSupported = IsThemingSupported();
Theme::Theme() : hTheme(NULL)
{
}
Theme::~Theme()
{
Close();
}
bool Theme::Open(HWND hWnd, LPCWSTR pszClassList)
{
if(!themingSupported) {
return false;
}
Close();
hTheme = OpenThemeData(hWnd, pszClassList);
return hTheme != NULL;
}
void Theme::Close()
{
if(!themingSupported) {
return;
}
if(hTheme != NULL) {
CloseThemeData(hTheme);
hTheme = NULL;
}
}
bool Theme::DrawBackground(HDC hDC, int iPartId, int iStateId, const RECT& rect,
const RECT* pClipRect) const
{
if(!themingSupported) {
return false;
}
return SUCCEEDED(DrawThemeBackground(hTheme, hDC, iPartId, iStateId, &rect,
pClipRect));
}
bool Theme::IsThemingSupported()
{
HINSTANCE hThemeDll = LoadLibrary(TEXT(uxtheme.dll));
if(hThemeDll != NULL) {
FreeLibrary(hThemeDll);
return true;
}
return false;
}
リンカの設定を忘れずに。
皆様、多くのサンプルありがとうございます。
だいぶ情報も集まってきてちょっと消化不良気味です…
ですが、学ぶべきことは見えてきたのでこれからも精進していきます。
本当にありがとうございました。