.net 2003 MFC使用。
CRecordsetを派生したクラスCRsHaseiをDLLで定義し、
Exe側ではそのクラスを以下のように使用
CRsHasei* pRs = new CRsHasei;
pRs ->Open();
pRs ->Close();
delete pRs;//ここでヒープエラー
DLLを使用しない場合はエラーになりません。
また、下記のようにオープン、クローズなしだとエラーになりません。
CRsHasei* pRs = new CRsHasei;
delete pRs;
原因や対応がわかりません。
よろしくお願い致します。
原因は、「delete pRs;」を行うタイミングで pRsを使っているので例外が
発生したんだと思います。
>CRsHasei* pRs = new CRsHasei;
DLL側で行う必要ありますか?
アプリケーション側なら、
「InitInstance()」でnewしてExitInstance()でdeleteすれば済みます。
DLLだとどこでどのタイミングで「CRsHasei」を使うか分りません。
すみません。ちょっと意味が理解できていないので、
ずれた返信かもしれませんが、
下記の処理は全てアプリケーション側で実行しています。
CRsHasei* pRs = new CRsHasei;
pRs ->Open();
pRs ->Close();
delete pRs;//ここでヒープエラー
>DLL側で行う必要ありますか?
これは上記の処理のことですか?CRsHaseiの定義のことですか?
>アプリケーション側なら、
>「InitInstance()」でnewしてExitInstance()でdeleteすれば済みます。
deleteはCRsHaseiを利用するクラスのデストラクタで実行したいと思っています。
よろしくお願いします。
>これは上記の処理のことですか?CRsHaseiの定義のことですか?
>CRsHasei* pRs = new CRsHasei;
>delete pRs;//ここでヒープエラー
この二つの文のことです。
>deleteはCRsHaseiを利用するクラスのデストラクタで実行したいと思っています。
今でもそうしていますか?
-----ココカラ------
pRs ->Open();
--処理---
pRs ->Close();
-----ココマデ---------
の処理にスレッドを使用していて、deleteする時に終わっていないとまずいですね。
単純に派生したクラスの実装に問題があってメモリの状態がおかしくなっているとかあり
えないですか?
何らかの処理をするとおかしくなるのであれば、ありえないこともなさそうな気がします
けれど。
実際の実装がどうなっているのかわからないので単なる想像ですけれど。
>CRsHasei* pRs = new CRsHasei;
>delete pRs;
上記はExe側で実行しています。
>deleteはCRsHaseiを利用するクラスのデストラクタで実行したいと思っています。
今でもそうしていますか?
はい。それにテストとして、通常の関数内でも試しています。
>-----ココカラ------
>pRs ->Open();
>--処理---
>pRs ->Close();
>-----ココマデ---------
>の処理にスレッドを使用していて、deleteする時に終わっていないとまずいですね。
そうなんでしょうか。DLLを使用しない場合はスレッドにしなくてもエラーになりませ
ん。
>単純に派生したクラスの実装に問題があってメモリの状態がおかしくなっているとかあ
>りえないですか?
>何らかの処理をするとおかしくなるのであれば、ありえないこともなさそうな気がしま
>すけれど。
処理をおっていったところ、メモリのアドレス(pRsの値)は変わっていませんでした。
テスト時はオープンとクローズの間に何もしていません。
ちなみにCRsHaseiを定義したDLL内ではdelete時にエラーになりません。
>そうなんでしょうか。DLLを使用しない場合はスレッドにしなくてもエラーになりませ
>ん。
すみません、文章がおかしかったです。
誤
>の処理にスレッドを使用していて、deleteする時に終わっていないとまずいですね。
正
の処理にスレッドを使用していた場合、deleteする時に終わっていないと
まずいですね。
>の処理にスレッドを使用していた場合、deleteする時に終わっていないと
まずいですね。
ああ、そういう意味ならそうですね。
ITOさんの最初の書き込みの意味も分かりましたが、多分そういう制限はないと思いま
す。DLLにしなければ問題ないですので。
DLLの作り方が悪いのかもしれません。
明日ソース載せますので、よろしくお願いします。
>処理をおっていったところ、メモリのアドレス(pRsの値)は変わっていませんでした。
これは良く考えたら当たり前で、pRsの指す目盛りの中身を見ないとだめですね。
以下ソースです。
------------------------------------------------------
//RsWrapper.h
#pragma once
#include < afxdb.h >
class DLL_EXPORT_INEMS CRsWrapper : public CRecordset
//DLL_EXPORT_INEMSはマクロで、DLLでは__declspec(dllexport)、
//Exeでは__declspec(dllimport)になります。
{
public:
CRsWrapper( CString p_cStrFolderPath, CString p_cStrFileName, CString
p_cStrTableName, CDatabase* p_pdb = NULL );
CRsWrapper( CString p_cStrFilePath, CString p_cStrTableName,
Database* p_pdb = NULL );
CRsWrapper( CDatabase* p_pdb = NULL );
virtual ~CRsWrapper();
DECLARE_DYNAMIC(CRsWrapper)
// オーバーライド
// ウィザードで生成された仮想関数のオーバーライド
public:
virtual CString GetDefaultConnect(); // 既定の接続文字列
virtual CString GetDefaultSQL(); // レコードセットの既定の SQL
virtual void vSetFolderPath( CString p_cStrFolderPath );
virtual void vSetFileName( CString p_cStrFileName );
virtual void vSetTableName( CString p_cStrTableName );
// 実装
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
};
//RsWrapper.cpp
#include stdafx.h
#include RsWrapper.h
IMPLEMENT_DYNAMIC( CRsWrapper, CRecordset )
CRsWrapper::CRsWrapper( CString p_cStrFolderPath, CString p_cStrFileName,
CString p_cStrTableName, CDatabase* p_pdb ): CRecordset( p_pdb )
{
vSetFolderPath( p_cStrFolderPath );
vSetFileName( p_cStrFileName );
vSetTableName( p_cStrTableName );
}
CRsWrapper::CRsWrapper( CString p_cStrFilePath, CString p_cStrTableName,
CDatabase* p_pdb ): CRecordset( p_pdb )
{
vSetFolderPath( CDevCommon::cStrAbstFolderPath( p_cStrFilePath ));
vSetFileName( CDevCommon::cStrAbstFileName( p_cStrFilePath ));
vSetTableName( p_cStrTableName );
}
CRsWrapper::CRsWrapper( CDatabase* p_pdb ) : CRecordset( p_pdb )
{
}
CRsWrapper::~CRsWrapper()
{
}
CString CRsWrapper::GetDefaultConnect()
{
return _T (ODBC;DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS
Access};DBQ=) + m_cStrFolderPath + \\ + m_cStrFileName;
}
CString CRsWrapper::GetDefaultSQL()
{
return _T([) + m_cStrTableName + _T(]);
}
void CRsWrapper::vSetFolderPath( CString p_cStrFolderPath )
{
m_cStrFolderPath = p_cStrFolderPath;
}
void CRsWrapper::vSetFileName( CString p_cStrFileName )
{
m_cStrFileName = p_cStrFileName;
}
void CRsWrapper::vSetTableName( CString p_cStrTableName )
{
m_cStrTableName = p_cStrTableName;
}
/////////////////////////////////////////////////////////////////////////////
// CRsWrapper 診断
#ifdef _DEBUG
void CRsWrapper::AssertValid() const
{
CRecordset::AssertValid();
}
void CRsWrapper::Dump(CDumpContext& dc) const
{
CRecordset::Dump(dc);
}
#endif //_DEBUG
気づいたのです、今までの例は若干実際とは違っていました。
実際は以下のとおりです。
CRsWrapper・・・DLLで定義
CRsHasei・・・Exeで定義
↓Exeで使用
CRsHasei* pRs = new CRsHasei;
pRs ->Open();
pRs ->Close();
delete pRs;//ここでヒープエラー
実際は、「CRsHasei」のクラスが、DLLn関数を動かしているのですね。
ところで、
>CRsHasei* pRs = new CRsHasei;
何のために必要なんですか?
普通に
CRsHasei* pRs = new CRsHasei;
では駄目ですか?
CRsHasei がアプリケーション上で動いている以上
わざわざ、newする必要がないと思います。
ヒープに移すほどの容量のメモリーを使っているのでしょうか?
普通にと言うのはこういうことですよね、多分。
CRsHasei Rs;
PATIOさん、フォロー有難う御座います。
>CRsHasei Rs;
すみません、間違っていました。