mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-29 11:53:23 +08:00
[0.2.x] ~ref: dia symbol loader
git-svn-id: https://pykd.svn.codeplex.com/svn@80119 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
parent
4cb4014242
commit
6c9444877d
203
pykd/dia/diaload.cpp
Normal file
203
pykd/dia/diaload.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
//
|
||||||
|
// Load debug symbols using DIA
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "dbghelp.h"
|
||||||
|
#include "dia/diawrapper.h"
|
||||||
|
#include "win/utils.h"
|
||||||
|
#include "dbgengine.h"
|
||||||
|
#include "diacallback.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace pykd {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace diaLoad {
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// DIA data source loader
|
||||||
|
interface IDataProvider
|
||||||
|
{
|
||||||
|
virtual ~IDataProvider() {}
|
||||||
|
virtual HRESULT load(__inout IDiaDataSource &DiaDataSource) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Load debug symbols using DIA
|
||||||
|
static SymbolSessionPtr createSession(
|
||||||
|
IDataProvider &DataProvider,
|
||||||
|
ULONGLONG loadBase
|
||||||
|
)
|
||||||
|
{
|
||||||
|
HRESULT hres;
|
||||||
|
DiaDataSourcePtr dataSource;
|
||||||
|
|
||||||
|
hres = dataSource.CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER);
|
||||||
|
|
||||||
|
if ( S_OK != hres )
|
||||||
|
throw DiaException("Call ::CoCreateInstance", hres);
|
||||||
|
|
||||||
|
hres = DataProvider.load(*dataSource);
|
||||||
|
if ( S_OK != hres )
|
||||||
|
throw DiaException("Call IDiaDataSource::loadDataXxx", hres);
|
||||||
|
|
||||||
|
DiaSessionPtr _session;
|
||||||
|
hres = dataSource->openSession(&_session);
|
||||||
|
if ( S_OK != hres )
|
||||||
|
throw DiaException("Call IDiaDataSource::openSession", hres);
|
||||||
|
|
||||||
|
hres = _session->put_loadAddress(loadBase);
|
||||||
|
if (S_OK != hres)
|
||||||
|
throw DiaException("Call IDiaSession::put_loadAddress", hres);
|
||||||
|
|
||||||
|
DiaSymbolPtr _globalScope;
|
||||||
|
hres = _session->get_globalScope(&_globalScope);
|
||||||
|
if ( S_OK != hres )
|
||||||
|
throw DiaException("Call IDiaSymbol::get_globalScope", hres);
|
||||||
|
|
||||||
|
return SymbolSessionPtr( new DiaSession( _session, _globalScope ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Load debug symbols using symbol file
|
||||||
|
class DataFromPdb : public IDataProvider {
|
||||||
|
std::wstring m_filePath;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DataFromPdb(__in const std::string &filePath) {
|
||||||
|
m_filePath = toWStr(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT load(__inout IDiaDataSource &dataSource) override {
|
||||||
|
return dataSource.loadDataFromPdb( m_filePath.c_str() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Access to executable file over RVA-callback
|
||||||
|
class ReadExeAtRVACallback : public IDiaReadExeAtRVACallback {
|
||||||
|
ULONGLONG m_loadBase;
|
||||||
|
int m_nRefCount;
|
||||||
|
CComPtr< IDiaLoadCallback2 > m_diaLoadCallback2;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ReadExeAtRVACallback(
|
||||||
|
__in ULONGLONG loadBase,
|
||||||
|
__out std::string &openedSymbolFile
|
||||||
|
) : m_loadBase(loadBase), m_nRefCount(1)
|
||||||
|
, m_diaLoadCallback2( new DiaLoadCallback2(&openedSymbolFile) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUnknown impl
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef() {
|
||||||
|
m_nRefCount++;
|
||||||
|
return m_nRefCount;
|
||||||
|
}
|
||||||
|
ULONG STDMETHODCALLTYPE Release() {
|
||||||
|
const int nRefCount = (--m_nRefCount);
|
||||||
|
if (!nRefCount)
|
||||||
|
delete this;
|
||||||
|
return nRefCount;
|
||||||
|
}
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID rid, void **ppUnk ) {
|
||||||
|
if ( ppUnk == NULL )
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
if (rid == __uuidof(IDiaReadExeAtRVACallback))
|
||||||
|
{
|
||||||
|
*ppUnk = this;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_diaLoadCallback2->QueryInterface(rid, ppUnk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDiaReadExeAtRVACallback impl
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE ReadExecutableAtRVA(
|
||||||
|
/* [in] */ DWORD relativeVirtualAddress,
|
||||||
|
/* [in] */ DWORD cbData,
|
||||||
|
/* [out] */ DWORD *pcbData,
|
||||||
|
/* [size_is][out] */ BYTE *pbData
|
||||||
|
) override {
|
||||||
|
return
|
||||||
|
readMemoryImpl(
|
||||||
|
m_loadBase + relativeVirtualAddress,
|
||||||
|
pbData,
|
||||||
|
cbData,
|
||||||
|
pcbData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load debug symbols using ReadExeAtRVACallback
|
||||||
|
struct DataForExeByRva : IDataProvider {
|
||||||
|
|
||||||
|
std::string m_openedSymbolFile;
|
||||||
|
|
||||||
|
DataForExeByRva(
|
||||||
|
__in ULONGLONG loadBase,
|
||||||
|
__in const std::string &executable,
|
||||||
|
__in const std::string &symbolSearchPath
|
||||||
|
) : m_loadBase(loadBase)
|
||||||
|
{
|
||||||
|
m_executable = toWStr(executable);
|
||||||
|
|
||||||
|
if (symbolSearchPath.empty())
|
||||||
|
m_symbolSearchPath = toWStr( getSymbolPath() );
|
||||||
|
else
|
||||||
|
m_symbolSearchPath = toWStr( symbolSearchPath );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT load(__inout IDiaDataSource &dataSource) override {
|
||||||
|
CComPtr< IUnknown > readExeAtRVACallback(new ReadExeAtRVACallback(m_loadBase, m_openedSymbolFile) );
|
||||||
|
return
|
||||||
|
dataSource.loadDataForExe(
|
||||||
|
m_executable.c_str(),
|
||||||
|
m_symbolSearchPath.c_str(),
|
||||||
|
readExeAtRVACallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ULONGLONG m_loadBase;
|
||||||
|
|
||||||
|
std::wstring m_executable;
|
||||||
|
std::wstring m_symbolSearchPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
} // namespace diaLoad
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase )
|
||||||
|
{
|
||||||
|
diaLoad::DataFromPdb dataFromPdb(filePath);
|
||||||
|
return diaLoad::createSession(dataFromPdb, loadBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SymbolSessionPtr loadSymbolFile(
|
||||||
|
__in ULONGLONG loadBase,
|
||||||
|
__in const std::string &executable,
|
||||||
|
__out std::string &loadedSymbolFile,
|
||||||
|
__in_opt std::string symbolSearchPath /*= std::string()*/
|
||||||
|
)
|
||||||
|
{
|
||||||
|
diaLoad::DataForExeByRva dataForExeByRva(loadBase, executable, symbolSearchPath);
|
||||||
|
|
||||||
|
SymbolSessionPtr symSession = diaLoad::createSession(dataForExeByRva, loadBase);
|
||||||
|
loadedSymbolFile = dataForExeByRva.m_openedSymbolFile;
|
||||||
|
return symSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
} // namespace pykd
|
@ -3,8 +3,6 @@
|
|||||||
#include "dbghelp.h"
|
#include "dbghelp.h"
|
||||||
#include "dia/diawrapper.h"
|
#include "dia/diawrapper.h"
|
||||||
#include "win/utils.h"
|
#include "win/utils.h"
|
||||||
#include "dbgengine.h"
|
|
||||||
#include "diacallback.h"
|
|
||||||
|
|
||||||
namespace pykd {
|
namespace pykd {
|
||||||
|
|
||||||
@ -92,24 +90,58 @@ std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres, ID
|
|||||||
}
|
}
|
||||||
sstream << "Return value is 0x" << std::hex << hres;
|
sstream << "Return value is 0x" << std::hex << hres;
|
||||||
|
|
||||||
PCHAR errMessage = NULL;
|
switch (hres)
|
||||||
FormatMessageA(
|
|
||||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
||||||
NULL,
|
|
||||||
hres,
|
|
||||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
||||||
(PCHAR)&errMessage,
|
|
||||||
0,
|
|
||||||
NULL);
|
|
||||||
if (errMessage)
|
|
||||||
{
|
{
|
||||||
sstream << ": " << std::endl;
|
#define _CASE_DIA_ERROR(x) case E_PDB_##x: sstream << ": E_PDB_" #x << std::endl; break
|
||||||
sstream << errMessage;
|
|
||||||
LocalFree(errMessage);
|
_CASE_DIA_ERROR(USAGE);
|
||||||
}
|
_CASE_DIA_ERROR(OUT_OF_MEMORY);
|
||||||
else
|
_CASE_DIA_ERROR(FILE_SYSTEM);
|
||||||
{
|
_CASE_DIA_ERROR(NOT_FOUND);
|
||||||
sstream << std::endl;
|
_CASE_DIA_ERROR(INVALID_SIG);
|
||||||
|
_CASE_DIA_ERROR(INVALID_AGE);
|
||||||
|
_CASE_DIA_ERROR(PRECOMP_REQUIRED);
|
||||||
|
_CASE_DIA_ERROR(OUT_OF_TI);
|
||||||
|
_CASE_DIA_ERROR(NOT_IMPLEMENTED);
|
||||||
|
_CASE_DIA_ERROR(V1_PDB);
|
||||||
|
_CASE_DIA_ERROR(FORMAT);
|
||||||
|
_CASE_DIA_ERROR(LIMIT);
|
||||||
|
_CASE_DIA_ERROR(CORRUPT);
|
||||||
|
_CASE_DIA_ERROR(TI16);
|
||||||
|
_CASE_DIA_ERROR(ACCESS_DENIED);
|
||||||
|
_CASE_DIA_ERROR(ILLEGAL_TYPE_EDIT);
|
||||||
|
_CASE_DIA_ERROR(INVALID_EXECUTABLE);
|
||||||
|
_CASE_DIA_ERROR(DBG_NOT_FOUND);
|
||||||
|
_CASE_DIA_ERROR(NO_DEBUG_INFO);
|
||||||
|
_CASE_DIA_ERROR(INVALID_EXE_TIMESTAMP);
|
||||||
|
_CASE_DIA_ERROR(RESERVED);
|
||||||
|
_CASE_DIA_ERROR(DEBUG_INFO_NOT_IN_PDB);
|
||||||
|
_CASE_DIA_ERROR(SYMSRV_BAD_CACHE_PATH);
|
||||||
|
_CASE_DIA_ERROR(SYMSRV_CACHE_FULL);
|
||||||
|
|
||||||
|
#undef _CASE_DIA_ERROR
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
PCHAR errMessage = NULL;
|
||||||
|
FormatMessageA(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
NULL,
|
||||||
|
hres,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(PCHAR)&errMessage,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
if (errMessage)
|
||||||
|
{
|
||||||
|
sstream << ": " << std::endl;
|
||||||
|
sstream << errMessage;
|
||||||
|
LocalFree(errMessage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sstream << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sstream.str();
|
return sstream.str();
|
||||||
@ -120,163 +152,6 @@ std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres, ID
|
|||||||
#define callSymbol(method) \
|
#define callSymbol(method) \
|
||||||
callSymbolT( &IDiaSymbol::##method, #method)
|
callSymbolT( &IDiaSymbol::##method, #method)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
interface IDiaLoadDataImpl
|
|
||||||
{
|
|
||||||
virtual ~IDiaLoadDataImpl() {}
|
|
||||||
virtual HRESULT load(__inout IDiaDataSource &DiaDataSource) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static SymbolSessionPtr loadDebugSymbols(
|
|
||||||
IDiaLoadDataImpl &LoadDataImpl,
|
|
||||||
ULONGLONG loadBase
|
|
||||||
)
|
|
||||||
{
|
|
||||||
HRESULT hres;
|
|
||||||
DiaDataSourcePtr dataSource;
|
|
||||||
|
|
||||||
hres = dataSource.CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER);
|
|
||||||
|
|
||||||
if ( S_OK != hres )
|
|
||||||
throw DiaException("Call ::CoCreateInstance", hres);
|
|
||||||
|
|
||||||
hres = LoadDataImpl.load(*dataSource);
|
|
||||||
if ( S_OK != hres )
|
|
||||||
throw DiaException("Call IDiaDataSource::loadDataXxx", hres);
|
|
||||||
|
|
||||||
DiaSessionPtr _session;
|
|
||||||
hres = dataSource->openSession(&_session);
|
|
||||||
if ( S_OK != hres )
|
|
||||||
throw DiaException("Call IDiaDataSource::openSession", hres);
|
|
||||||
|
|
||||||
hres = _session->put_loadAddress(loadBase);
|
|
||||||
if (S_OK != hres)
|
|
||||||
throw DiaException("Call IDiaSession::put_loadAddress", hres);
|
|
||||||
|
|
||||||
DiaSymbolPtr _globalScope;
|
|
||||||
hres = _session->get_globalScope(&_globalScope);
|
|
||||||
if ( S_OK != hres )
|
|
||||||
throw DiaException("Call IDiaSymbol::get_globalScope", hres);
|
|
||||||
|
|
||||||
return SymbolSessionPtr( new DiaSession( _session, _globalScope ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase )
|
|
||||||
{
|
|
||||||
struct LoadDataFromPdb : IDiaLoadDataImpl, boost::noncopyable
|
|
||||||
{
|
|
||||||
const std::string &m_filePath;
|
|
||||||
LoadDataFromPdb(const std::string &filePath) : m_filePath(filePath) {}
|
|
||||||
|
|
||||||
virtual HRESULT load(__inout IDiaDataSource &dataSource) override
|
|
||||||
{
|
|
||||||
return dataSource.loadDataFromPdb( toWStr(m_filePath) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LoadDataFromPdb loadDataFromPdb(filePath);
|
|
||||||
|
|
||||||
return loadDebugSymbols(loadDataFromPdb, loadBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
SymbolSessionPtr loadSymbolFile(
|
|
||||||
__in ULONGLONG loadBase,
|
|
||||||
__in const std::string &executable,
|
|
||||||
__out std::string &loadedSymbolFile,
|
|
||||||
__in_opt std::string symbolSearchPath /*= std::string()*/
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (symbolSearchPath.empty())
|
|
||||||
symbolSearchPath = getSymbolPath();
|
|
||||||
|
|
||||||
class ReadExeAtRVACallback : public IDiaReadExeAtRVACallback
|
|
||||||
{
|
|
||||||
ULONGLONG m_loadBase;
|
|
||||||
int m_nRefCount;
|
|
||||||
CComPtr< IDiaLoadCallback2 > m_diaLoadCallback2;
|
|
||||||
public:
|
|
||||||
ReadExeAtRVACallback(ULONGLONG loadBase, std::string &openedSymbolFile)
|
|
||||||
: m_loadBase(loadBase), m_nRefCount(1), m_diaLoadCallback2(new DiaLoadCallback2(&openedSymbolFile))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() {
|
|
||||||
m_nRefCount++;
|
|
||||||
return m_nRefCount;
|
|
||||||
}
|
|
||||||
ULONG STDMETHODCALLTYPE Release() {
|
|
||||||
const int nRefCount = (--m_nRefCount);
|
|
||||||
if (!nRefCount)
|
|
||||||
delete this;
|
|
||||||
return nRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID rid, void **ppUnk ) {
|
|
||||||
if ( ppUnk == NULL )
|
|
||||||
return E_INVALIDARG;
|
|
||||||
|
|
||||||
if (rid == __uuidof(IDiaReadExeAtRVACallback))
|
|
||||||
{
|
|
||||||
*ppUnk = this;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_diaLoadCallback2->QueryInterface(rid, ppUnk);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual HRESULT STDMETHODCALLTYPE ReadExecutableAtRVA(
|
|
||||||
/* [in] */ DWORD relativeVirtualAddress,
|
|
||||||
/* [in] */ DWORD cbData,
|
|
||||||
/* [out] */ DWORD *pcbData,
|
|
||||||
/* [size_is][out] */ BYTE *pbData
|
|
||||||
) override
|
|
||||||
{
|
|
||||||
return
|
|
||||||
readMemoryImpl(
|
|
||||||
m_loadBase + relativeVirtualAddress,
|
|
||||||
pbData,
|
|
||||||
cbData,
|
|
||||||
pcbData);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LoadDataForExeByRva : IDiaLoadDataImpl, boost::noncopyable
|
|
||||||
{
|
|
||||||
ULONGLONG m_loadBase;
|
|
||||||
const std::string &m_executable;
|
|
||||||
const std::string &m_symbolSearchPath;
|
|
||||||
std::string m_openedSymbolFile;
|
|
||||||
|
|
||||||
LoadDataForExeByRva(ULONGLONG loadBase, const std::string &executable, std::string symbolSearchPath)
|
|
||||||
: m_loadBase(loadBase), m_executable(executable), m_symbolSearchPath(symbolSearchPath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual HRESULT load(__inout IDiaDataSource &dataSource) override
|
|
||||||
{
|
|
||||||
CComPtr< IUnknown > readExeAtRVACallback(new ReadExeAtRVACallback(m_loadBase, m_openedSymbolFile) );
|
|
||||||
return
|
|
||||||
dataSource.loadDataForExe(
|
|
||||||
toWStr(m_executable),
|
|
||||||
toWStr(m_symbolSearchPath),
|
|
||||||
readExeAtRVACallback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LoadDataForExeByRva loadDataForExeByRva(loadBase, executable, symbolSearchPath);
|
|
||||||
|
|
||||||
SymbolSessionPtr symSession = loadDebugSymbols(loadDataForExeByRva, loadBase);
|
|
||||||
loadedSymbolFile = loadDataForExeByRva.m_openedSymbolFile;
|
|
||||||
return symSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::string getBasicTypeName( ULONG basicType )
|
std::string getBasicTypeName( ULONG basicType )
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="windows-1251"?>
|
<?xml version="1.0" encoding="windows-1251"?>
|
||||||
<VisualStudioProject
|
<VisualStudioProject
|
||||||
ProjectType="Visual C++"
|
ProjectType="Visual C++"
|
||||||
Version="9,00"
|
Version="9.00"
|
||||||
Name="pykd"
|
Name="pykd"
|
||||||
ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
|
ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
|
||||||
RootNamespace="pykd"
|
RootNamespace="pykd"
|
||||||
@ -617,6 +617,10 @@
|
|||||||
RelativePath=".\dia\diadata.cpp"
|
RelativePath=".\dia\diadata.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\dia\diaload.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\dia\diawrapper.cpp"
|
RelativePath=".\dia\diawrapper.cpp"
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user