811 lines
21 KiB
C++
811 lines
21 KiB
C++
|
// QueryDB.cpp: Database querying methods.
|
||
|
#include "stdafx.h"
|
||
|
#include "AppParseWeb.h"
|
||
|
#include "AppParseWrapper.h"
|
||
|
#include <oledb.h>
|
||
|
#include <comdef.h>
|
||
|
#include <mshtml.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
// Progress dialog functions
|
||
|
void InitProgressDialog(char* szText, HANDLE hEvent);
|
||
|
void KillProgressDialog();
|
||
|
|
||
|
// Return true if name matches search string, false otherwise.
|
||
|
bool MatchName(char* szString, char* szSearchIn);
|
||
|
|
||
|
// Tree used to represent parse information
|
||
|
class CTreeNode
|
||
|
{
|
||
|
private:
|
||
|
enum {c_Root, c_Project, c_Module, c_Function} m_eType;
|
||
|
|
||
|
int m_nChildren;
|
||
|
CTreeNode** m_ppChildren;
|
||
|
|
||
|
// Relevent info retrieved from DB
|
||
|
union
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
char szName[256];
|
||
|
long lPtolemyID;
|
||
|
} m_ProjectInfo;
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
char szName[256];
|
||
|
} m_ModuleInfo;
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
char szName[256];
|
||
|
} m_FunctionInfo;
|
||
|
};
|
||
|
|
||
|
// HTML generation members
|
||
|
|
||
|
// Unique table and div ID's.
|
||
|
static int m_iCurrDiv;
|
||
|
static int m_iCurrTab;
|
||
|
|
||
|
// Amount of space set aside for HTML content.
|
||
|
static int m_iAllocSize;
|
||
|
|
||
|
// Pointer to HTML content.
|
||
|
static char* m_szHTML;
|
||
|
// Pointer to where the more HTML should be inserted.
|
||
|
static char* m_szCurrHTML;
|
||
|
|
||
|
// Pointer a few kilobytes before the end of the HTML buffer, reaching
|
||
|
// here means we should allocate more space.
|
||
|
static char* m_szFencePost;
|
||
|
|
||
|
// True if this node or one of its subtrees contains the function, false otherwise.
|
||
|
bool ContainsFunction(char* szFuncName)
|
||
|
{
|
||
|
if(m_eType == c_Function)
|
||
|
return MatchName(m_FunctionInfo.szName, szFuncName);
|
||
|
|
||
|
for(int i = 0; i < m_nChildren; i++)
|
||
|
{
|
||
|
if(m_ppChildren[i]->ContainsFunction(szFuncName))
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Write all HTML output
|
||
|
void WriteHTML()
|
||
|
{
|
||
|
static int iDepth = 0;
|
||
|
switch(m_eType)
|
||
|
{
|
||
|
case c_Root:
|
||
|
break;
|
||
|
case c_Project:
|
||
|
|
||
|
// Create a new table and Div in the project
|
||
|
m_iCurrTab++;
|
||
|
m_iCurrDiv++;
|
||
|
|
||
|
wsprintf(m_szCurrHTML,
|
||
|
"<table ID = TAB%d border = 1 width = 100%% style=\"float:right\">\n"
|
||
|
"<tr>\n<td width=1%%>\n"
|
||
|
"<input type=\"button\" ID=DIV%dButton value = \"+\" "
|
||
|
"onClick=\"ShowItem(\'DIV%d\')\">"
|
||
|
"</td>\n"
|
||
|
"<td>%s</td><td width=20%%>%d</td>\n</tr>\n"
|
||
|
"</table>\n"
|
||
|
"<DIV ID=DIV%d style=\"display:none;\">\n",
|
||
|
m_iCurrTab, m_iCurrDiv, m_iCurrDiv,
|
||
|
m_ProjectInfo.szName, m_ProjectInfo.lPtolemyID,
|
||
|
m_iCurrDiv);
|
||
|
|
||
|
m_szCurrHTML += strlen(m_szCurrHTML);
|
||
|
|
||
|
break;
|
||
|
case c_Module:
|
||
|
// Create a new table and div in the project
|
||
|
m_iCurrTab++;
|
||
|
m_iCurrDiv++;
|
||
|
|
||
|
wsprintf(m_szCurrHTML,
|
||
|
"<table ID = TAB%d border = 1 width = %d%% style=\"float:right\">\n"
|
||
|
"<tr>\n<td width=1%%>"
|
||
|
"<input type=\"button\" ID=DIV%dButton value = \"+\" "
|
||
|
"onClick=\"ShowItem(\'DIV%d\')\">"
|
||
|
"</td>\n"
|
||
|
"<td>%s</td>\n</tr>\n"
|
||
|
"</table>\n"
|
||
|
"<DIV ID=DIV%d style=\"display:none;\">\n",
|
||
|
m_iCurrTab, 100-iDepth*5, m_iCurrDiv, m_iCurrDiv,
|
||
|
m_ModuleInfo.szName, m_iCurrDiv );
|
||
|
|
||
|
m_szCurrHTML += strlen(m_szCurrHTML);
|
||
|
|
||
|
break;
|
||
|
case c_Function:
|
||
|
// Create a new table in the project
|
||
|
m_iCurrTab++;
|
||
|
wsprintf(m_szCurrHTML,
|
||
|
"<table ID = TAB%d border = 1 width = %d%% style=\"float:right\">\n"
|
||
|
"<tr>"
|
||
|
"<td>%s</td>\n</tr>\n"
|
||
|
"</table>\n",
|
||
|
m_iCurrTab, 100-iDepth*5, m_FunctionInfo.szName);
|
||
|
m_szCurrHTML += strlen(m_szCurrHTML);
|
||
|
break;
|
||
|
default:
|
||
|
assert(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Put in all the HTML for the children
|
||
|
if(m_ppChildren)
|
||
|
{
|
||
|
iDepth++;
|
||
|
for(int i = 0; i < m_nChildren; i++)
|
||
|
m_ppChildren[i]->WriteHTML();
|
||
|
|
||
|
iDepth--;
|
||
|
}
|
||
|
|
||
|
switch(m_eType)
|
||
|
{
|
||
|
case c_Function:
|
||
|
case c_Root:
|
||
|
break;
|
||
|
case c_Project:
|
||
|
case c_Module:
|
||
|
wsprintf(m_szCurrHTML, "</DIV>\n");
|
||
|
m_szCurrHTML += strlen(m_szCurrHTML);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Check if we should allocate more
|
||
|
if(m_szCurrHTML > m_szFencePost)
|
||
|
{
|
||
|
m_iAllocSize *= 2;
|
||
|
char* szNewBuffer = new char[m_iAllocSize];
|
||
|
m_szFencePost = &szNewBuffer[m_iAllocSize - 2 * 1024];
|
||
|
strcpy(szNewBuffer, m_szHTML);
|
||
|
m_szCurrHTML = &szNewBuffer[strlen(szNewBuffer)];
|
||
|
delete m_szHTML;
|
||
|
m_szHTML = szNewBuffer;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
public:
|
||
|
CTreeNode()
|
||
|
{
|
||
|
m_eType = c_Root;
|
||
|
m_nChildren = 0;
|
||
|
m_ppChildren = 0;
|
||
|
assert(m_eType < 50);
|
||
|
}
|
||
|
|
||
|
CTreeNode(SProjectRecord pr)
|
||
|
{
|
||
|
m_eType = c_Project;
|
||
|
m_nChildren = 0;
|
||
|
m_ppChildren = 0;
|
||
|
strcpy(m_ProjectInfo.szName, pr.Name);
|
||
|
m_ProjectInfo.lPtolemyID = pr.PtolemyID;
|
||
|
assert(m_eType < 50);
|
||
|
}
|
||
|
|
||
|
CTreeNode(SModuleRecord mr)
|
||
|
{
|
||
|
m_eType = c_Module;
|
||
|
m_nChildren = 0;
|
||
|
m_ppChildren = 0;
|
||
|
strcpy(m_ModuleInfo.szName, mr.Name);
|
||
|
assert(m_eType < 50);
|
||
|
}
|
||
|
|
||
|
CTreeNode(SFunctionRecord fr)
|
||
|
{
|
||
|
m_eType = c_Function;
|
||
|
m_nChildren = 0;
|
||
|
m_ppChildren = 0;
|
||
|
strcpy(m_FunctionInfo.szName, fr.Name);
|
||
|
assert(m_eType < 50);
|
||
|
}
|
||
|
|
||
|
~CTreeNode()
|
||
|
{
|
||
|
RemoveChildren();
|
||
|
}
|
||
|
|
||
|
// Remove tree nodes that contain no nodes matching the search criteria.
|
||
|
// Returns true if node should be removed, false otherwise.
|
||
|
bool Prune(char* szFunc)
|
||
|
{
|
||
|
assert(m_eType < 50);
|
||
|
// Go through each child
|
||
|
for(int i = 0; i < m_nChildren; i++)
|
||
|
{
|
||
|
// Check if needs to be removed
|
||
|
if(m_ppChildren[i]->Prune(szFunc))
|
||
|
{
|
||
|
// Remove this child.
|
||
|
delete m_ppChildren[i];
|
||
|
m_ppChildren[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Update the child list
|
||
|
int nChildren = 0;
|
||
|
for(i = 0; i < m_nChildren; i++)
|
||
|
{
|
||
|
if(m_ppChildren[i])
|
||
|
nChildren++;
|
||
|
}
|
||
|
|
||
|
if(nChildren)
|
||
|
{
|
||
|
CTreeNode** pNew = new CTreeNode*[nChildren];
|
||
|
int iCurr = 0;
|
||
|
for(i = 0; i < m_nChildren; i++)
|
||
|
{
|
||
|
if(m_ppChildren[i])
|
||
|
{
|
||
|
pNew[iCurr++] = m_ppChildren[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete m_ppChildren;
|
||
|
m_ppChildren = pNew;
|
||
|
|
||
|
assert(iCurr == nChildren);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(m_ppChildren)
|
||
|
{
|
||
|
delete m_ppChildren;
|
||
|
m_ppChildren = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_nChildren = nChildren;
|
||
|
|
||
|
// If we contain no children and we're not a function, we should be removed.
|
||
|
if(m_nChildren == 0 && m_eType != c_Function)
|
||
|
return true;
|
||
|
|
||
|
// Return whether we don't contain the function or not.
|
||
|
return !ContainsFunction(szFunc);
|
||
|
}
|
||
|
|
||
|
// Return a string representing the HTML representation of this tree.
|
||
|
char* GetHTML()
|
||
|
{
|
||
|
// Should only be called on root.
|
||
|
assert(m_eType == c_Root);
|
||
|
|
||
|
// Initially reserve space for 64K of HTML.
|
||
|
m_iAllocSize = 64 * 1024;
|
||
|
if(m_szHTML)
|
||
|
delete m_szHTML;
|
||
|
|
||
|
m_szHTML = new char[m_iAllocSize];
|
||
|
m_szHTML[0] = '\0';
|
||
|
m_szCurrHTML = m_szHTML;
|
||
|
m_szFencePost = &m_szHTML[m_iAllocSize - 2 * 1024];
|
||
|
|
||
|
// Fill it with the HTML for this node and all child nodes.
|
||
|
WriteHTML();
|
||
|
|
||
|
char* szRet = m_szHTML;
|
||
|
|
||
|
m_szHTML = 0;
|
||
|
|
||
|
return szRet;
|
||
|
}
|
||
|
|
||
|
// Remove all children from this node.
|
||
|
void RemoveChildren()
|
||
|
{
|
||
|
assert(m_eType < 50);
|
||
|
while(m_nChildren)
|
||
|
{
|
||
|
delete m_ppChildren[m_nChildren-1];
|
||
|
m_ppChildren[m_nChildren-1] = 0;
|
||
|
m_nChildren--;
|
||
|
}
|
||
|
if(m_ppChildren)
|
||
|
delete m_ppChildren;
|
||
|
|
||
|
m_ppChildren = 0;
|
||
|
assert(m_eType < 50);
|
||
|
}
|
||
|
|
||
|
// Insert a new child.
|
||
|
void InsertChild(CTreeNode* pNew)
|
||
|
{
|
||
|
assert(pNew);
|
||
|
assert(pNew->m_eType < 50);
|
||
|
m_nChildren++;
|
||
|
CTreeNode** pNewList = new CTreeNode*[m_nChildren];
|
||
|
|
||
|
if(m_ppChildren)
|
||
|
{
|
||
|
memcpy(pNewList, m_ppChildren, (m_nChildren-1)*sizeof(CTreeNode*));
|
||
|
delete m_ppChildren;
|
||
|
}
|
||
|
m_ppChildren = pNewList;
|
||
|
m_ppChildren[m_nChildren-1] = pNew;
|
||
|
assert(m_eType < 50);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Define the static members of CTreeNode
|
||
|
int CTreeNode::m_iCurrDiv = 0;
|
||
|
int CTreeNode::m_iCurrTab = 0;
|
||
|
int CTreeNode::m_iAllocSize = 0;
|
||
|
char* CTreeNode::m_szHTML = 0;
|
||
|
char* CTreeNode::m_szCurrHTML = 0;
|
||
|
char* CTreeNode::m_szFencePost = 0;
|
||
|
|
||
|
// Global tree info.
|
||
|
CTreeNode g_InfoTreeRoot;
|
||
|
|
||
|
// Return true if name matches search string, false otherwise.
|
||
|
bool MatchName(char* szString, char* szSearchIn)
|
||
|
{
|
||
|
if(strcmp(szSearchIn, "*") == 0)
|
||
|
return true;
|
||
|
|
||
|
char* szSearch = szSearchIn;
|
||
|
while(*szSearch != '\0' && *szString != '\0')
|
||
|
{
|
||
|
// If we get a ?, we don't care and move on to the next
|
||
|
// character.
|
||
|
if(*szSearch == '?')
|
||
|
{
|
||
|
szSearch++;
|
||
|
szString++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// If we have a wildcard, move to next search string and search for substring
|
||
|
if(*szSearch == '*')
|
||
|
{
|
||
|
char* szCurrSearch;
|
||
|
szSearch++;
|
||
|
|
||
|
if(*szSearch == '\0')
|
||
|
return true;
|
||
|
|
||
|
// Don't change starting point.
|
||
|
szCurrSearch = szSearch;
|
||
|
for(;;)
|
||
|
{
|
||
|
// We're done if we hit another wildcard
|
||
|
if(*szCurrSearch == '*' ||
|
||
|
*szCurrSearch == '?')
|
||
|
{
|
||
|
// Update the permanent search position.
|
||
|
szSearch = szCurrSearch;
|
||
|
break;
|
||
|
}
|
||
|
// At end of both strings, return true.
|
||
|
if((*szCurrSearch == '\0') && (*szString == '\0'))
|
||
|
return true;
|
||
|
|
||
|
// We never found it
|
||
|
if(*szString == '\0')
|
||
|
return false;
|
||
|
|
||
|
// If it doesn't match, start over
|
||
|
if(toupper(*szString) != toupper(*szCurrSearch))
|
||
|
{
|
||
|
// If mismatch on first character
|
||
|
// of search string, move to next
|
||
|
// character in function string.
|
||
|
if(szCurrSearch == szSearch)
|
||
|
szString++;
|
||
|
else
|
||
|
szCurrSearch = szSearch;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
szString++;
|
||
|
szCurrSearch++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(toupper(*szString) != toupper(*szSearch))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
szString++;
|
||
|
szSearch++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if((*szString == 0) && ((*szSearch == '\0') || (strcmp(szSearch,"*")==0)))
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Add all functions from a module to the tree.
|
||
|
void BuildFunctions(long lParentID, CTreeNode* pParent, _ConnectionPtr pConn)
|
||
|
{
|
||
|
_RecordsetPtr pFunctions = 0;
|
||
|
pFunctions.CreateInstance(__uuidof(Recordset));
|
||
|
char szQuery[1024];
|
||
|
|
||
|
// Open a recordset of all functions that match
|
||
|
wsprintf(szQuery, "SELECT * FROM FUNCTIONS WHERE MODULEID = %d", lParentID);
|
||
|
|
||
|
pFunctions->Open(szQuery, variant_t((IDispatch*)pConn, true), adOpenKeyset,
|
||
|
adLockOptimistic, adCmdText);
|
||
|
|
||
|
|
||
|
// Bind the record set to a local structure.
|
||
|
IADORecordBinding* pRBFunctions = 0;
|
||
|
HRESULT hr = pFunctions->QueryInterface(__uuidof(IADORecordBinding),
|
||
|
reinterpret_cast<void**>(&pRBFunctions));
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to acquire record binding interface", hr);
|
||
|
|
||
|
SFunctionRecord fr;
|
||
|
|
||
|
hr = pRBFunctions->BindToRecordset(&fr);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to bind recordset", hr);
|
||
|
|
||
|
// Go through each record in the set
|
||
|
VARIANT_BOOL fEOF;
|
||
|
pFunctions->get_EndOfFile(&fEOF);
|
||
|
while(!fEOF)
|
||
|
{
|
||
|
// Create a new node.
|
||
|
CTreeNode* pNewNode = new CTreeNode(fr);
|
||
|
pParent->InsertChild(pNewNode);
|
||
|
|
||
|
pFunctions->MoveNext();
|
||
|
pFunctions->get_EndOfFile(&fEOF);
|
||
|
}
|
||
|
|
||
|
pFunctions->Close();
|
||
|
|
||
|
SafeRelease(pRBFunctions);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Add all modules to the tree.
|
||
|
void BuildModules(long lParentID, CTreeNode* pParent, bool fTopLevel,
|
||
|
_ConnectionPtr pConn, HANDLE hEvent)
|
||
|
{
|
||
|
// Check if we should termiante early.
|
||
|
if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
|
||
|
return;
|
||
|
|
||
|
_RecordsetPtr pModules = 0;
|
||
|
pModules.CreateInstance(__uuidof(Recordset));
|
||
|
char szQuery[1024];
|
||
|
|
||
|
// Get recordset that matches
|
||
|
if(fTopLevel)
|
||
|
wsprintf(szQuery, "SELECT * FROM MODULES WHERE PTOLEMYID = %d", lParentID);
|
||
|
else
|
||
|
wsprintf(szQuery, "SELECT * FROM MODULES WHERE PARENTID = %d", lParentID);
|
||
|
|
||
|
|
||
|
pModules->Open(szQuery, variant_t((IDispatch*)pConn, true), adOpenKeyset,
|
||
|
adLockOptimistic, adCmdText);
|
||
|
|
||
|
|
||
|
IADORecordBinding* pRBModules = 0;
|
||
|
HRESULT hr = pModules->QueryInterface(__uuidof(IADORecordBinding),
|
||
|
reinterpret_cast<void**>(&pRBModules));
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to acquire record binding interface", hr);
|
||
|
|
||
|
SModuleRecord mr;
|
||
|
|
||
|
hr = pRBModules->BindToRecordset(&mr);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to bind recordset", hr);
|
||
|
|
||
|
// Go through each record
|
||
|
VARIANT_BOOL fEOF;
|
||
|
pModules->get_EndOfFile(&fEOF);
|
||
|
while(!fEOF)
|
||
|
{
|
||
|
// Insert into tree
|
||
|
CTreeNode* pNewNode = new CTreeNode(mr);
|
||
|
pParent->InsertChild(pNewNode);
|
||
|
|
||
|
// Build all child modules
|
||
|
BuildModules(mr.ModuleID, pNewNode, false, pConn, hEvent);
|
||
|
|
||
|
// Build all functions
|
||
|
BuildFunctions(mr.ModuleID, pNewNode, pConn);
|
||
|
|
||
|
pModules->MoveNext();
|
||
|
pModules->get_EndOfFile(&fEOF);
|
||
|
}
|
||
|
|
||
|
pModules->Close();
|
||
|
|
||
|
SafeRelease(pRBModules);
|
||
|
}
|
||
|
|
||
|
// Add a project to the tree
|
||
|
void BuildProjects(long PtolemyID, char* szFunc, _ConnectionPtr pConn, HANDLE hEvent)
|
||
|
{
|
||
|
assert(PtolemyID > 0);
|
||
|
|
||
|
// Check if we should terminate early
|
||
|
if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
|
||
|
return;
|
||
|
|
||
|
_RecordsetPtr pProjects = 0;
|
||
|
pProjects.CreateInstance(__uuidof(Recordset));
|
||
|
char szQuery[1024];
|
||
|
|
||
|
// Get a recordset that matches
|
||
|
wsprintf(szQuery, "SELECT * FROM PROJECTS WHERE PTOLEMYID = %d", PtolemyID);
|
||
|
|
||
|
pProjects->Open(szQuery, variant_t((IDispatch*)pConn, true),adOpenKeyset,
|
||
|
adLockOptimistic, adCmdText);
|
||
|
|
||
|
IADORecordBinding* pRBProjects = 0;
|
||
|
HRESULT hr = pProjects->QueryInterface(__uuidof(IADORecordBinding),
|
||
|
reinterpret_cast<void**>(&pRBProjects));
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to acquire record binding interface", hr);
|
||
|
|
||
|
SProjectRecord pr;
|
||
|
|
||
|
hr = pRBProjects->BindToRecordset(&pr);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to bind recordset", hr);
|
||
|
|
||
|
VARIANT_BOOL fEOF;
|
||
|
pProjects->get_EndOfFile(&fEOF);
|
||
|
while(!fEOF)
|
||
|
{
|
||
|
// Insert the node at the root.
|
||
|
CTreeNode* pNewNode = new CTreeNode(pr);
|
||
|
g_InfoTreeRoot.InsertChild(pNewNode);
|
||
|
|
||
|
// Get all child modules
|
||
|
BuildModules(pr.PtolemyID, pNewNode, true, pConn, hEvent);
|
||
|
|
||
|
// Save memory by trimming tree now.
|
||
|
pNewNode->Prune(szFunc);
|
||
|
|
||
|
pProjects->MoveNext();
|
||
|
pProjects->get_EndOfFile(&fEOF);
|
||
|
}
|
||
|
|
||
|
pProjects->Close();
|
||
|
|
||
|
SafeRelease(pRBProjects);
|
||
|
}
|
||
|
|
||
|
long GetModulePtolemy(long lModuleID, _ConnectionPtr pConn)
|
||
|
{
|
||
|
_RecordsetPtr pModules = 0;
|
||
|
pModules.CreateInstance(__uuidof(Recordset));
|
||
|
char szQuery[1024];
|
||
|
|
||
|
// Get a single record recordset containing the module.
|
||
|
wsprintf(szQuery, "SELECT * FROM MODULES WHERE MODULEID = %d", lModuleID);
|
||
|
|
||
|
pModules->Open(szQuery, variant_t((IDispatch*)pConn, true), adOpenKeyset,
|
||
|
adLockOptimistic, adCmdText);
|
||
|
|
||
|
IADORecordBinding* pRBModules = 0;
|
||
|
HRESULT hr = pModules->QueryInterface(__uuidof(IADORecordBinding),
|
||
|
reinterpret_cast<void**>(&pRBModules));
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to acquire record binding interface", hr);
|
||
|
|
||
|
SModuleRecord mr;
|
||
|
|
||
|
hr = pRBModules->BindToRecordset(&mr);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to bind recordset", hr);
|
||
|
|
||
|
|
||
|
// Either return ptolemy ID, if valid, otherwise call on parent module.
|
||
|
long lParent = mr.ParentID;
|
||
|
if(mr.ParentIDStatus != adFldNull)
|
||
|
{
|
||
|
pModules->Close();
|
||
|
SafeRelease(pRBModules);
|
||
|
return GetModulePtolemy(lParent, pConn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pModules->Close();
|
||
|
SafeRelease(pRBModules);
|
||
|
return lParent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long GetFuncPtolemy(SFunctionRecord fr, _ConnectionPtr pConn)
|
||
|
{
|
||
|
return GetModulePtolemy(fr.ModuleID, pConn);
|
||
|
}
|
||
|
|
||
|
// Build a list projects that contain a function that matches szFunc.
|
||
|
void BuildProjectsFromFunction(char* szFunc, _ConnectionPtr pConn, HANDLE hEvent)
|
||
|
{
|
||
|
// Check if we should terminate early.
|
||
|
if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
|
||
|
return;
|
||
|
|
||
|
_RecordsetPtr pFunctions = 0;
|
||
|
pFunctions.CreateInstance(__uuidof(Recordset));
|
||
|
char* szQuery = "SELECT * FROM FUNCTIONS";
|
||
|
|
||
|
pFunctions->Open(szQuery, variant_t((IDispatch*)pConn, true),adOpenKeyset,
|
||
|
adLockOptimistic, adCmdText);
|
||
|
|
||
|
IADORecordBinding* pRBFunctions = 0;
|
||
|
HRESULT hr = pFunctions->QueryInterface(__uuidof(IADORecordBinding),
|
||
|
reinterpret_cast<void**>(&pRBFunctions));
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to acquire record binding interface", hr);
|
||
|
|
||
|
SFunctionRecord fr;
|
||
|
|
||
|
hr = pRBFunctions->BindToRecordset(&fr);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to bind recordset", hr);
|
||
|
|
||
|
VARIANT vtBookMark;
|
||
|
hr = pFunctions->get_Bookmark(&vtBookMark);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to get recordset bookmark", hr);
|
||
|
|
||
|
// Do a search for the function
|
||
|
char szFind[512];
|
||
|
int FunctionList[1024] = {0};
|
||
|
wsprintf(szFind, "Name like \'%s\'", szFunc);
|
||
|
pFunctions->Find(szFind, 0, adSearchForward, vtBookMark);
|
||
|
while(!pFunctions->EndOfFile)
|
||
|
{
|
||
|
|
||
|
// Get which module imports this function
|
||
|
long lPtolemy = GetFuncPtolemy(fr, pConn);
|
||
|
assert(lPtolemy > 0);
|
||
|
|
||
|
// Make sure we haven't already touched this module.
|
||
|
bool fInUse = false;
|
||
|
for(int i = 0; i < 1024; i++)
|
||
|
{
|
||
|
if(FunctionList[i] == 0)
|
||
|
{
|
||
|
FunctionList[i] = lPtolemy;
|
||
|
break;
|
||
|
}
|
||
|
else if(FunctionList[i] == lPtolemy)
|
||
|
{
|
||
|
fInUse = true;
|
||
|
}
|
||
|
}
|
||
|
if(!fInUse)
|
||
|
BuildProjects(lPtolemy, szFunc, pConn, hEvent);
|
||
|
|
||
|
hr = pFunctions->get_Bookmark(&vtBookMark);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to acquire recordset bookmark", hr);
|
||
|
pFunctions->Find(szFind, 1, adSearchForward, vtBookMark);
|
||
|
}
|
||
|
|
||
|
SafeRelease(pRBFunctions);
|
||
|
pFunctions->Close();
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CAppParse::QueryDB(long PtolemyID, BSTR bstrFunction)
|
||
|
{
|
||
|
assert(m_hEvent);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// Start cancelation dialog
|
||
|
ResetEvent(m_hEvent);
|
||
|
InitProgressDialog("Querying database . . .", m_hEvent);
|
||
|
|
||
|
bstr_t bszFunctionSearch = bstrFunction;
|
||
|
|
||
|
char* szFunctionSearch = static_cast<char*>(bszFunctionSearch);
|
||
|
|
||
|
HRESULT hr;
|
||
|
|
||
|
_ConnectionPtr pConn = 0;
|
||
|
|
||
|
pConn.CreateInstance(__uuidof(Connection));
|
||
|
|
||
|
// Connect to the DB
|
||
|
pConn->Open(m_szConnect, "","", adConnectUnspecified);
|
||
|
|
||
|
// Build projects
|
||
|
if(PtolemyID > 0)
|
||
|
BuildProjects(PtolemyID, szFunctionSearch, pConn, m_hEvent);
|
||
|
else
|
||
|
BuildProjectsFromFunction(szFunctionSearch, pConn, m_hEvent);
|
||
|
|
||
|
pConn->Close();
|
||
|
|
||
|
// Check if results should be shown.
|
||
|
if(WaitForSingleObject(m_hEvent, 0) == WAIT_OBJECT_0)
|
||
|
{
|
||
|
g_InfoTreeRoot.RemoveChildren();
|
||
|
KillProgressDialog();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Trim the tree down.
|
||
|
g_InfoTreeRoot.Prune(szFunctionSearch);
|
||
|
|
||
|
// Get our container document.
|
||
|
CComPtr<IOleContainer> pContainer = 0;
|
||
|
|
||
|
m_spClientSite->GetContainer(&pContainer);
|
||
|
CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> pDoc(pContainer);
|
||
|
if(!pDoc)
|
||
|
APError("Unable to acquire container HTML document", E_FAIL);
|
||
|
|
||
|
CComPtr<IHTMLElementCollection> pElements;
|
||
|
pDoc->get_all(&pElements);
|
||
|
CComPtr<IDispatch> pDispatch = 0;
|
||
|
|
||
|
// Get the element that will contain all HTML output (the "Results" DIV)
|
||
|
hr = pElements->item(variant_t("Results"), variant_t(0L), &pDispatch);
|
||
|
|
||
|
if(FAILED(hr) || !pDispatch)
|
||
|
return E_FAIL;
|
||
|
|
||
|
CComQIPtr<IHTMLElement, &IID_IHTMLElement> pDivElem(pDispatch);
|
||
|
|
||
|
// Get HTML representation of tree.
|
||
|
char* szHTML = g_InfoTreeRoot.GetHTML();
|
||
|
|
||
|
// Convert to wide characters
|
||
|
OLECHAR* oszInnerHTML = new OLECHAR[strlen(szHTML) + 1];
|
||
|
|
||
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szHTML,
|
||
|
-1, oszInnerHTML,
|
||
|
(strlen(szHTML)+1)*sizeof(OLECHAR));
|
||
|
|
||
|
delete szHTML;
|
||
|
|
||
|
// Convert to a BSTR
|
||
|
BSTR bszInnerHTML = SysAllocString(oszInnerHTML);
|
||
|
delete oszInnerHTML;
|
||
|
|
||
|
// Write the HTML into the document.
|
||
|
hr = pDivElem->put_innerHTML(bszInnerHTML);
|
||
|
if(FAILED(hr))
|
||
|
APError("Unable to write HTML to container document", hr);
|
||
|
|
||
|
SysFreeString(bszInnerHTML);
|
||
|
}
|
||
|
catch(_com_error& e)
|
||
|
{
|
||
|
::MessageBox(0, (LPCSTR)e.ErrorMessage(), "COM Error", MB_OK);
|
||
|
}
|
||
|
|
||
|
g_InfoTreeRoot.RemoveChildren();
|
||
|
KillProgressDialog();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|