“test-jb-setup”
http://www-01.ibm.com/support/knowledgecenter/SSYJ99_8.5.0/install/prep_dom.dita
http://www.kalechi.com/doc/notesini.nsf/85255a87005060c585255a850068ca6f/75d2a021772c9edbc1256d71006fc6f9!OpenDocument
“test-jb-setup”
有一个需求,要统计所用用户的邮件大小和限额,并导出成报表
第一个想到的方案,是通过NotesDatabase对象,获取数据库属性等。具体方法有2种:
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim directory As NotesDbDirectory
Set directory = New NotesDbDirectory("test/test")
Set db = directory.GetFirstDatabase( Database )
Dim dbMax As Double
Dim dbSize As Double
Do While Not (db Is Nothing)
On Error Resume Next
'Call db.OpenMail 'you have to open the db to get the size property
dbmax = (db.sizequota)/1024 'puts quota into Megs
dbsize = (db.size)/1024 'puts size into kb
dbsize = Round( (dbsize/1024), 0 ) 'puts size into mb, rounds to nearest Integer
MsgBox db.Filepath + " -- " + CStr(dbsize)
Set db = directory.GetNextDatabase 'get the next database
Loop
End Sub
这里有一个比较有意思的,如果加了
Call db.OpenMail
数据库路径就一直是当前用户
做法相差不大,相对NotesDbDirectory多了一个视图和文档的开销。
问题是什么呢。
这2种方式都需要运行代理的人,需要有权限获取这个数据库
基于前面的尝试(心里还是很不甘心的,先解决问题吧)。想起来为什么WebAdmin可以获取这些数据库大小。然后开始扒拉代码。因为是要获取限额,所以直接搜索quota就找到了。
原理其实比较简单,直接通过控制台命令
show directory 目录 -xml
就可以了。
Show Directory
[017E:0003-01CF] | DbName | Version | Logged |
---|---|---|---|
[017E:0003-01CF] | f:\notefile\schema50.nsf | V5:41 | Yes |
[017E:0003-01CF] | f:\notefile\Stats.box | V5:27 | No |
<?xml version="1.0" encoding="UTF-8" ?>
<files xmlns="http://www.lotus.com/dxl/console">
<filedata notesversion="8" odsversion="51" logged="disabled" backup="no" id="48257E59:00313CF5" link="1" dboptions="268443648,21626880,57348,0">
<replica id="48257873:001E7AEF" flags="56" count="1">
<cutoff interval="90">20150217T025339,84+08</cutoff>
</replica>
<path>/notesdata/mail/test1.nsf</path>
<name>test1.nsf</name>
<title>test1</title>
<template></template>
<inheritedtemplate>Mail6</inheritedtemplate>
<category></category>
<size current="2643984384" max="0" usage="2640352256"/>
<quota limit="0" warning="0"/>
<created>20150603T165748,69+08</created>
<lastcompact></lastcompact>
<unread marks="yes" replicate="never"/>
<daos enabled="no"/>
<pirc enabled="no"/>
</filedata>
<filedata notesversion="8" odsversion="51" logged="disabled" backup="no" id="48257E3B:002BE00F" link="1" dboptions="0,21626880,108774,0">
<replica id="48257E3B:002BDB28" flags="8" count="1">
<cutoff interval="90">20150306T022916,12+08</cutoff>
</replica>
<path>/notesdata/mail/test2.nsf</path>
<name>test2.nsf</name>
<title>test2</title>
<template></template>
<inheritedtemplate>StdR85Mail/zh-CN</inheritedtemplate>
<category></category>
<size current="13369344" max="0" usage="13093888"/>
<quota limit="0" warning="0"/>
<created>20150504T155914,07+08</created>
<lastcompact></lastcompact>
<unread marks="yes" replicate="all"/>
<daos enabled="no"/>
<pirc enabled="no"/>
</filedata>
从这个结构里面,我们其实获取了数据库的当前大小和限额,速度非常快。有了这个结构以后,就需要开始解析xml。
lotusscript的解析其实是比较怪异的,下标是从1开始的。
下面是主角登场,阉割过的版本,如果找不到完整的,可以联系我。
Const CONSOLE_XML = "-xml"
Private Type TypeFileData
sPath As String
sName As String
dSize As Double
dSizeUsed As Double
lSizeMax As Long
lQuotaLimit As Long
lQuotaWarning As Long
End Type
Private Class cFileData
Private m_session As NotesSession
Public Sub New
On Error GoTo ERROR_HANDLER
Set m_session = New NotesSession
Exit Sub
ERROR_HANDLER:
Exit Sub
End Sub
public Sub GetDirectoryData(sServer As String , sPath As String,lsDB List As TypeFileData )
On Error GoTo ERROR_HANDLER
Dim tFD As TypeFileData
Dim sResponse As String
Dim sCmd As String
Dim DOMParser As NotesDOMParser
Dim DOMDocument As NotesDOMDocumentNode
Dim DOMAttributes As NotesDOMNamedNodeMap
Dim DOMNodeList As NotesDOMNodeList
Dim DOMNode As NotesDOMNode
Dim sAttribName As String
Dim sAttribText As String
Dim sNodeName As String
Dim sNodeText As String
Dim lNodeIndex As Long
Dim lAttribIndex As Long
Dim iIndex As Integer
Dim CONSOLE_PREFIX As String
sCmd = CONSOLE_PREFIX + |show directory "| + sPath + |" | + CONSOLE_XML
sResponse = m_session.SendConsoleCommand(sServer, sCmd)
Set DOMParser = m_session.CreateDOMParser
Call DOMParser.Setinput(sResponse)
Call DOMParser.Process()
Set DOMDocument = DOMParser.Document
Set DOMNodeList = DOMDocument.GetElementsByTagName("filedata")
For lNodeIndex = 1 To DOMNodeList.NumberOfEntries
tFD.sPath = ""
tFD.sName = ""
tFD.dSize = 0
tFD.dSizeUsed = 0
tFD.lSizeMax = 0
tFD.lQuotaLimit = 0
tFD.lQuotaWarning = 0
'loop all child nodes of <filedata>
Set DOMNode = DOMNodeList.GetItem(lNodeIndex).FirstChild
Do While Not DOMNode.isNull
If DOMNode.nodeType = DOMNodeType_Element_Node Then
sNodeName = DOMNode.nodeName
Select Case sNodeName
Case "size":
Set DOMAttributes = DOMNode.Attributes
For lAttribIndex = 1 To DOMAttributes.NumberOfEntries
sAttribName = DOMAttributes.GetItem(lAttribIndex).NodeName
sAttribText = DOMAttributes.GetItem(lAttribIndex).NodeValue
Select Case sAttribName
Case "current": tFD.dSize = CDbl(sAttribText)
Case "usage": tFD.dSizeUsed = CDbl(sAttribText)
Case "max": tFD.lSizeMax = CLng(sAttribText)
End Select
Next lAttribIndex
Case "quota":
Set DOMAttributes = DOMNode.Attributes
For lAttribIndex = 1 To DOMAttributes.NumberOfEntries
sAttribName = DOMAttributes.GetItem(lAttribIndex).NodeName
sAttribText = DOMAttributes.GetItem(lAttribIndex).NodeValue
Select Case sAttribName
Case "limit": tFD.lQuotaLimit = CLng(sAttribText)
Case "warning": tFD.lQuotaWarning = CLng(sAttribText)
End Select
Next lAttribIndex
End Select
'textual values of a node are stored off in a childnode
If DOMNode.HasChildNodes Then
sNodeText = DOMNode.firstChild.nodeValue
Select Case sNodeName
Case "path": tFD.sPath = sNodeText
Case "name": tFD.sName = sNodeText
Case "title": tFD.sTitle = sNodeText
Case "template": tFD.sTemplate = sNodeText
Case "inheritedtemplate": tFD.sTemplInherited = sNodeText
Case "category": tFD.sType = sNodeText
End Select
End If
End If
Set DOMNode = DOMNode.NextSibling
lsDB(sServer + tfd.sName).dSize = tfd.dSize
lsDB(sServer + tfd.sName).dSizeUsed = tFd.dSizeUsed
lsDB(sServer + tfd.sName).lQuotaLimit = tFd.lQuotaLimit
lsDB(sServer + tfd.sName).sPath = tFd.sPath
lsDB(sServer + tfd.sName).sName = tFd.sname
lsDB(sServer + tfd.sName).lSizeMax = tFd.lSizeMax
lsDB(sServer + tfd.sName).lQuotaWarning = tFd.lQuotaWarning
Loop
Next lNodeIndex
Exit Sub
ERROR_HANDLER:
Exit Sub
End Sub
End Class
如何使用,其实比较简单,
Dim fd As New cFileData
Dim lsFD List As TypeFileData
Call fd.GetDirectoryData("mailserver", "mail", lsFD)
msgbox lsFD("test1.nsf").sName + " -----"
“test-jb-setup”
断断续续做了很多年的OA,伴随整个OA生涯的是Office的研发,算是一个回忆吧。
通常Office控件分2种。
嵌入
嵌入方式比较好理解,就是在ActiveX控件里面显示Word内容。
VC的版本,在微软早起有一个dso的源码。给大家很多思路。
Delphi版本一般是直接使用OLEContainer控件。
不管用哪种方式,开发成本都是不低的。如果是Delphi的版本,基本也需要自己重写这个对象了。 国内2个比较有代表性的商业产品正好是2个不同的思路。
独立 独立的意思是单独启动Office进程,然后进行交互。首当其冲的问题是如何获取Office对象,并进而让ActiveX和这个对象建立联系。
2种方式都经历过,用得比较多的还是第2种方式。
如果能获取到IDispath接口,就可以和Delphi自己的WordApplication建立关联,也就能捕获Office的事件。
通过Javascript把word对象传入到ActiveX控件中。
unit uCoGetServerPID;
// The web page is at http://www.winwonk.com/writing/cogetserverpid/
interface
uses Windows;
function CoGetServerPID (const unk: IUnknown; var dwPID: DWORD): HRESULT;
implementation
uses ActiveX, ComObj, Variants;
type
// Used to verify the COM object's signature and to sniff the PID out of the header.
TComObjRefHdr = packed record
signature: DWORD; // Should be 'MEOW'
padding : array[0..47] of Byte;
pid : WORD;
end;
PComObjRefHdr = ^TComObjRefHdr;
function CoGetServerPID(const unk: IUnknown; var dwPID: DWORD): HRESULT;
var
PObjRefHdr : PComObjRefHdr;
spProxyManager : IUnknown;
spMarshalStream : IStream;
liNewPos : Int64;
HG : HGLOBAL;
const
IID_IUnknown: TGUID = (D1:$00000000;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));
begin
if VarIsNULL(unk) then begin
Result := E_INVALIDARG;
Exit;
end;
// Check if not standard proxy. We can't make any assumptions about remote PID
Result := unk.QueryInterface(IID_IProxyManager, spProxyManager);
if Failed(Result) then Exit;
// Marshall the interface to get a new OBJREF
Result := CreateStreamOnHGlobal(0, True, spMarshalStream);
if Failed(Result) then Exit;
Result := CoMarshalInterface(spMarshalStream, IID_IUnknown, unk, MSHCTX_INPROC, nil, MSHLFLAGS_NORMAL);
if Failed(Result) then Exit;
// We just created the stream. So go back to a raw pointer.
Result := GetHGlobalFromStream(spMarshalStream, HG);
if Succeeded(Result) then try
// Start out pessimistic
Result := RPC_E_INVALID_OBJREF;
PObjRefHdr := GlobalLock(HG);
if Assigned(PObjRefHdr) then begin
// Verify that the signature is MEOW
if PObjRefHdr^.signature = $574f454d then begin
// We got the remote PID
dwPID := PObjRefHdr^.pid;
Result := S_OK;
end;
end;
finally
GlobalUnlock(HG);
end;
// Rewind stream and release marshal data to keep refcount in order
liNewPos := 0;
spMarshalStream.Seek(0, STREAM_SEEK_SET, liNewPos);
CoReleaseMarshalData(spMarshalStream);
end;
end.
procedure TMainForm.Button3Click(Sender: TObject);
Const OBJID_NATIVEOM : Integer = $fffffff0;
var
WordObject: IDispatch; // IDispatch;
hWindow: hWnd;
FDispatcher: TWordDocumentEventDispatcher;
WordApp: _Application;
begin
hWindow := GetWordHandle(Trim(LabeledEdit1.Text));
ForegroundWindow(true, hWindow);
hWindow := GetChildWndHandle(hWindow, '_WwG');
if AccessibleObjectFromWindow(hWindow, OBJID_NATIVEOM, IID_IDispatch, WordObject) = S_OK
then
begin
Caption := GetActiveDocPath(WordObject);
GetProperty(WordObject, 'ActiveDocument', WordObject);
caption := GetActiveDocPath(WordObject);
InterfaceConnect(WordObject, WordDocEventIID, FDispatcher, FConnection);
end
end;
function TMainForm.GetWordHandle(AFileName, AClassName, AFlagText: Widestring)
: NativeUInt;
var
Handle: NativeUInt;
sCaption: array [0 .. 1023] of char;
sClassName: array [0 .. 254] of char;
begin
Handle := FindWindowW(PWideChar(AClassName), nil);
while Handle <> 0 do
begin
FillChar(sClassName, Sizeof(sClassName), #0);
FillChar(sCaption, Sizeof(sCaption), #0);
GetClassName(Handle, sClassName, Sizeof(sClassName));
if sClassName = AClassName then
begin
GetWindowText(Handle, sCaption, Sizeof(sCaption));
if (Pos(AFileName, sCaption) > 0) and (Pos(AFlagText, sCaption) > 0)
then
begin
Result := Handle;
Exit;
end;
end;
Handle := GetWindow(Handle, GW_HWNDNEXT);
end;
Result := 0;
end;
function EnumWindowsProc(Wnd: DWORD; var EI: TEnumInfo): BOOL; stdcall;
var
Buf: array [0 .. 127] of widechar;
begin
GetClassNameW(Wnd, Buf, 128);
if Pos(Buf, EI.ClassName) > 0 then
begin
EI.hWnd := Wnd;
Result := FALSE;
Exit;
end;
Result := true;
end;
function TMainForm.GetChildWndHandle(AParentHandle: THandle; AClassName: string): THandle;
var
EI: TEnumInfo;
begin
EI.hWnd := 0;
EI.ClassName := AClassName;
EnumChildWindows(AParentHandle, @EnumWindowsProc, Integer(@EI));
Result := EI.hWnd;
end;
function GetProperty(dispobj: IDispatch; PropertyName: Widestring;
var retvalue: IDispatch): Boolean;
var
hr: HResult;
DispId1: Integer;
value: Variant;
Params: TDISPPARAMS;
typeInfo: ITypeInfo;
FuncDesc: pFuncDesc;
begin
Result := FALSE;
dispobj.GetTypeInfoCount(DispId1);
dispobj.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, typeInfo);
typeInfo.GetFuncDesc(0, FuncDesc);
//typeInfo.GetNames()
//ShowMessage(IntToStr(DispId1));
hr := dispobj.GetIDsOfNames(GUID_Null, @(PropertyName), 1,
LOCALE_SYSTEM_DEFAULT, @DispId1);
if (hr >= 0) then
begin
hr := dispobj.Invoke(DispId1, GUID_Null, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET, Params, @value, nil, nil);
if (hr >= 0) then
begin
retvalue := value;
Result := true;
end;
end;
end;
另外一个封装的东西
unit uDispatchLib;
interface
uses
ActiveX,
sysutils,
classes,
Windows,
oleacc;
type
exMethodNotSupported = class(Exception);
exIDispatchCallError = class(Exception);
function ExecuteOnDispatchMultiParam(TargetObj: IDispatch; MethodName: string;
ParamValues: array of const): OleVariant;
procedure DocumentIDispatch(ID: IDispatch; var SL: TStringList);
procedure DocumentIDispatch2(ID: IDispatch; var SLNames: TStringList);
function ElementDescriptionToString(a: TElemDesc): string;
procedure DisplayInfo(const aAccessible : IAccessible; const aOffset : string; slInterfaceinfo: TStringList);
function AccessibleObjectFromWindow(AHWnd: hWnd; dwObjectID: DWORD;
const riid: TGUID; out ppvObject): HResult; stdcall;
external 'OLEACC.DLL' name 'AccessibleObjectFromWindow';
function AccessibleChildren(paccContainer: Pointer; iChildStart: LONGINT;
cChildren: LONGINT; out rgvarChildren: OleVariant; out pcObtained: LONGINT)
: HResult; stdcall; external 'OLEACC.DLL' name 'AccessibleChildren';
const
OBJID_NATIVEOM = $FFFFFFF0;
IID_IDispatch: TGUID = '{00020400-0000-0000-C000-000000000046}';
implementation
uses
Variants;
function ElementDescriptionToString(a: TElemDesc): string;
begin
case a.tdesc.vt of
VT_I4:
Result := 'int';
VT_R8:
Result := 'double';
VT_BSTR:
Result := 'string';
else
Result := '';
end;
end;
procedure DocumentIDispatch(ID: IDispatch; var SL: TStringList);
var
res: HResult;
Count, loop, loop2, loop3: integer;
TI: ITypeinfo;
pTA: PTypeAttr;
pFD: PFuncDesc;
varDesc: pVarDesc;
numFunctions: integer;
numParams: integer;
funcDispID: integer;
names: TBStrList;
numReturned: integer;
functionstr: widestring;
hide: boolean;
begin
assert(SL <> nil, 'SL may not be nil');
SL.Clear;
res := ID.GetTypeInfoCount(Count);
if succeeded(res) then begin
for loop := 0 to Count - 1 do begin
res := ID.GetTypeInfo(loop, 0, TI);
if succeeded(res) then begin
res := TI.GetTypeAttr(pTA);
if succeeded(res) then begin
if pTA^.typekind = TKIND_DISPATCH then begin
numFunctions := pTA^.cFuncs;
for loop2 := 0 to numFunctions - 1 do begin
res := TI.GetFuncDesc(loop2, pFD);
if succeeded(res) then begin
funcDispID := pFD^.memid;
numParams := pFD^.cParams;
res := TI.GetNames(funcDispID, @names,
numParams + 1, numReturned);
if succeeded(res) then begin
functionstr := '';
if numReturned > 0 then
functionstr := functionstr + names[0];
if numReturned > 1 then begin
functionstr := functionstr + '(';
for loop3 := 1 to numReturned - 1 do
begin
if loop3 > 1 then
functionstr := functionstr + ', ';
functionstr := functionstr +
names[loop3] + ':' +
ElementDescriptionToString
(pFD^.lprgelemdescParam^[loop3 - 1]);
end;
// functionstr := functionstr + names[numReturned - 1] + ')';
functionstr := functionstr + ')';
end;
hide := False;
// Hides the non-dispatch functions
if (pFD^.wFuncFlags and
FUNCFLAG_FRESTRICTED) = FUNCFLAG_FRESTRICTED
then
hide := True;
// Hides the functions not intended for scripting: basically redundant functions
if (pFD^.wFuncFlags and FUNCFLAG_FHIDDEN) = FUNCFLAG_FHIDDEN
then
hide := True;
if not hide then
SL.add(functionstr);
end;
TI.ReleaseFuncDesc(pFD);
end;
end;
end;
TI.ReleaseTypeAttr(pTA);
end;
end;
end;
end
else
raise Exception.Create('GetTypeInfoCount Failed');
end;
procedure DocumentIDispatch2(ID: IDispatch; var SLNames: TStringList);
var
res: HResult;
Count, loop, loop2, loop3: integer;
TI: ITypeinfo;
pTA: PTypeAttr;
pFD: PFuncDesc;
varDesc: pVarDesc;
numFunctions: integer;
numParams: integer;
funcDispID: integer;
names: TBStrList;
numReturned: integer;
functionstr: widestring;
hide: boolean;
begin
SLNames.Clear;
res := ID.GetTypeInfoCount(Count);
if succeeded(res) then begin
for loop := 0 to Count - 1 do begin
res := ID.GetTypeInfo(loop, 0, TI);
if succeeded(res) then begin
res := TI.GetTypeAttr(pTA);
if succeeded(res) then begin
if pTA^.typekind = TKIND_DISPATCH then begin
numFunctions := pTA^.cFuncs;
for loop2 := 0 to numFunctions - 1 do begin
res := TI.GetFuncDesc(loop2, pFD);
if not succeeded(res) then
Continue;
funcDispID := pFD^.memid;
numParams := pFD^.cParams;
res := TI.GetNames(funcDispID, @names,
numParams + 1, numReturned);
if not succeeded(res) then begin
TI.ReleaseFuncDesc(pFD);
Continue;
end;
// Hides the non-dispatch functions
if (pFD^.wFuncFlags and FUNCFLAG_FRESTRICTED) = FUNCFLAG_FRESTRICTED
then
Continue;
// Hides the functions not intended for scripting: basically redundant functions
if (pFD^.wFuncFlags and FUNCFLAG_FHIDDEN) = FUNCFLAG_FHIDDEN
then
Continue;
functionstr := '';
if numReturned > 0 then begin
functionstr := functionstr + names[0];
end;
functionstr := functionstr + '(';
if numReturned > 1 then begin
for loop3 := 1 to numReturned - 1 do begin
if loop3 > 1 then
functionstr := functionstr + ',';
functionstr := functionstr +
ElementDescriptionToString
(pFD^.lprgelemdescParam^[loop3 - 1]);
end;
end;
SLNames.add(functionstr + ')');
TI.ReleaseFuncDesc(pFD);
end;
end;
TI.ReleaseTypeAttr(pTA);
end;
end;
end;
end
else
raise Exception.Create('GetTypeInfoCount Failed');
end;
{ ////////////////////////////////////////////////////////////////
Name: ExecuteOnDispatchMultiParam
Purpose:
To execute arbitrary method on given COM object.
Author: VJ
Date: 07.07.2001
History:
//////////////////////////////////////////////////////////////// }
function ExecuteOnDispatchMultiParam(TargetObj: IDispatch; MethodName: string;
ParamValues: array of const): OleVariant;
var
wide: widestring;
disps: TDispIDList;
panswer: ^OleVariant;
answer: OleVariant;
dispParams: TDispParams;
aexception: TExcepInfo;
pVarArg: PVariantArgList;
res: HResult;
ParamCount, I: integer;
begin
Result := False;
// prepare for function call
ParamCount := High(ParamValues) + 1;
wide := MethodName;
pVarArg := nil;
if ParamCount > 0 then
GetMem(pVarArg, ParamCount * sizeof(TVariantArg));
try
// get dispid of requested method
if not succeeded(TargetObj.GetIDsOfNames(GUID_NULL, @wide, 1, 0, @disps))
then
raise exMethodNotSupported.Create
('This object does not support this method');
panswer := @answer;
// prepare parameters
for I := 0 to ParamCount - 1 do begin
case ParamValues[ParamCount - 1 - I].VType of
vtInteger: begin
pVarArg^[I].vt := VT_I4;
pVarArg^[I].lVal :=
ParamValues[ParamCount - 1 - I].VInteger;
end;
vtExtended: begin
pVarArg^[I].vt := VT_R8;
pVarArg^[I].dblVal := ParamValues[ParamCount - 1 - I]
.VExtended^;
end;
vtString, vtAnsiString, vtChar: begin
pVarArg^[I].vt := VT_BSTR;
pVarArg^[I].bstrVal :=
PWideChar(widestring
(PChar(ParamValues[ParamCount - 1 - I].VString)));
end;
else
raise Exception.CreateFmt
('Unsuported type for parameter with index %d', [I]);
end;
end;
// prepare dispatch parameters
dispParams.rgvarg := pVarArg;
dispParams.rgdispidNamedArgs := nil;
dispParams.cArgs := ParamCount;
dispParams.cNamedArgs := 0;
// make IDispatch call
res := TargetObj.Invoke(disps[0], GUID_NULL, 0, DISPATCH_METHOD or
DISPATCH_PROPERTYGET, dispParams, panswer, @aexception, nil);
// check the result
if res <> 0 then
raise exIDispatchCallError.CreateFmt
('Method call unsuccessfull. %s (%s).',
[string(aexception.bstrDescription),
string(aexception.bstrSource)]);
// return the result
Result := answer;
finally
if ParamCount > 0 then
FreeMem(pVarArg, ParamCount * sizeof(TVariantArg));
end;
end;
procedure DisplayInfo(const aAccessible : IAccessible; const aOffset : string; slInterfaceinfo: TStringList);
procedure ProcessChild(const aChild : OleVariant);
var
ChildAccessible : IAccessible;
ChildDispatch : IDispatch;
begin
ChildDispatch := nil;
case VarType(aChild) of
varInteger : aAccessible.Get_accChild(aChild, ChildDispatch);
varDispatch : ChildDispatch := aChild;
end;
if (ChildDispatch <> nil) and (ChildDispatch.QueryInterface(IAccessible, ChildAccessible) = S_OK) then
DisplayInfo(ChildAccessible, aOffset + ' ', slInterfaceInfo)
end;
var
Child, CurrentChild : OleVariant;
ChildArray : array of OleVariant;
dwNum : DWord;
Enum : IEnumVARIANT;
i, iChildCount, iObtained : Integer;
wsText : WideString;
begin
if aAccessible <> nil then begin
if aAccessible.get_AccName(CHILDID_SELF, wsText) = S_OK then
slInterfaceInfo.Add(aOffset + 'Name: ' + wsText)
else
slInterfaceInfo.Add(aOffset + 'Name: Empty');
if aAccessible.get_AccValue(CHILDID_SELF, wsText) = S_OK then
slInterfaceInfo.Add(aOffset + ' Value: ' + wsText);
if aAccessible.get_AccDescription(CHILDID_SELF, wsText) = S_OK then
slInterfaceInfo.Add(aOffset + ' Description: ' + wsText);
if (aAccessible.Get_accChildCount(iChildCount) = S_OK) and (iChildCount > 0) then begin
slInterfaceInfo.Add(aOffset + ' Children: ' + IntToStr(iChildCount));
SetLength(ChildArray, iChildCount);
if AccessibleChildren(Pointer(aAccessible), 0, iChildCount, ChildArray[0], iObtained) = S_OK then begin
for i := 0 to iObtained - 1 do
ProcessChild(ChildArray[i])
end else if aAccessible.QueryInterface(IEnumVARIANT, Enum) = S_OK then begin
Enum := aAccessible as IEnumVARIANT;
for i := 0 to iChildCount - 1 do
if Enum.Next(1, Child, dwNum) = S_OK then
ProcessChild(Child);
end else begin
if aAccessible.accNavigate(NAVDIR_FIRSTCHILD, CHILDID_SELF, CurrentChild) = S_OK then begin
repeat
ProcessChild(CurrentChild)
until aAccessible.accNavigate(NAVDIR_NEXT, CurrentChild, CurrentChild) <> S_OK;
end
end
end
end
end;
end.
“test-jb-setup” #
其他的几个没装,好像也没用到
2种方案
cd ~/<my_working _directory>
git clone https://github.com/Itseez/opencv.git
cd ~/opencv
mkdir release
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ..
make && make install
http://sourceforge.net/projects/opencvlibrary/files/3rdparty/ippicv/
java.library.path问题
无法调用自己写的so文件
可以修改/etc/profile。导出一个变量 LD_LIBRARY_PATH
可以写个简单程序,确定一下是否可以了
javac test.java
java test # 这里不要加.class
System.setProperty("java.library.path")
通过这个查看,
strings /lib64/libc.so.6 |grep GLIBC_
2. 版本查找
rpm -qa |grep glibc
3. 手工编译
下载地址 <http://www.gnu.org/software/libc/>
mkdir build
cd build
../configure --prefix=/opt/glibc-2.14
make -j4
make install
4. 导出路径
export LD_LIBRARY_PATH=/opt/glibc-2.14/lib:$LD_LIBRARY_PATH
这个有个坑爹的东西,直接加到系统变量里面,结果系统都进不了中文环境了,一直报GUI错什么的,后来只是临时export一下,倒是可以了
在查看模式下,输入
可以组合
如果遇到需要强制退出的,比如修改了内容,不想保存,就在后面加感叹号
在查看模式下,直接敲 yy 或者 yyn n表示要复制的行数 在需要粘贴的地方,敲p,直接就粘贴过来了
查看模式下
在visual状态下,用 <或者>可以缩进,不过好像只能缩进一次 通常根据语言特征使用自动缩进排版:在命令状态下对当前行用== (连按=两次), 或对多行用n==(n是自然数)表示自动缩进从当前行起的下面n行。你可以试试把代码缩进任意打乱再用n==排版,相当于一般IDE里的code format。使用gg=G可对整篇代码进行排版。
在非编辑状态下,输入命令
%s/原始字符串/替换字符串/g
这里
搜索范围
最开始的%s是限定范围,表示整个文件,常用限定条件
替换范围
最后的g是全局的意思,限定范围的全局替换。 如果不加,就只替换第一个符合的字符串
如果没有后面的替换字符串,就仅仅是查找。
前翻后翻
# 向上搜索 N 向下搜索
替换行首行尾
在当前文件的所有行首插入字符“a”,可以用如下命令:
:%s/^/a
又如,在当前文件的所有行尾追加字符“b”,可用如下命令:
:%s/$/b
其中的^和$就分别是正则表达式中表示行首和行尾的表达式。
批量注释 :27,30s#^#//#g
在VIM中进行文本替换:
1. 替换当前行中的内容: :s/from/to/ (s即substitude)
:s/from/to/ : 将当前行中的第一个from,替换成to。如果当前行含有多个
from,则只会替换其中的第一个。
:s/from/to/g : 将当前行中的所有from都替换成to。
:s/from/to/gc : 将当前行中的所有from都替换成to,但是每一次替换之前都
会询问请求用户确认此操作。
注意:这里的from和to都可以是任何字符串,其中from还可以是正则表达式。
2. 替换某一行的内容: :33s/from/to/g
:.s/from/to/g : 在当前行进行替换操作。
:33s/from/to/g : 在第33行进行替换操作。
:$s/from/to/g : 在最后一行进行替换操作。
3. 替换某些行的内容: :10,20s/from/to/g
:10,20s/from/to/g : 对第10行到第20行的内容进行替换。
:1,$s/from/to/g : 对第一行到最后一行的内容进行替换(即全部文本)。
:1,.s/from/to/g : 对第一行到当前行的内容进行替换。
:.,$s/from/to/g : 对当前行到最后一行的内容进行替换。
:'a,'bs/from/to/g : 对标记a和b之间的行(含a和b所在的行)进行替换。
其中a和b是之前用m命令所做的标记。
4. 替换所有行的内容: :%s/from/to/g
:%s/from/to/g : 对所有行的内容进行替换。
5. 替换命令的完整形式: :[range]s/from/to/[flags]
5.1 s/from/to/
把from指定的字符串替换成to指定的字符串,from可以是正则表达式。
5.2 [range]
有以下一些表示方法:
不写range : 默认为光标所在的行。
. : 光标所在的行。
1 : 第一行。
$ : 最后一行。
33 : 第33行。
'a : 标记a所在的行(之前要使用ma做过标记)。
.+1 : 当前光标所在行的下面一行。
$-1 : 倒数第二行。(这里说明我们可以对某一行加减某个数值来
取得相对的行)。
22,33 : 第22~33行。
1,$ : 第1行 到 最后一行。
1,. : 第1行 到 当前行。
.,$ : 当前行 到 最后一行。
'a,'b : 标记a所在的行 到 标记b所在的行。
% : 所有行(与 1,$ 等价)。
?chapter? : 从当前位置向上搜索,找到的第一个chapter所在的行。(
其中chapter可以是任何字符串或者正则表达式。
/chapter/ : 从当前位置向下搜索,找到的第一个chapter所在的行。(
其中chapter可以是任何字符串或者正则表达式。
注意,上面的所有用于range的表示方法都可以通过 +、- 操作来设置相对偏
移量。
5.3 [flags]
这里可用的flags有:
无 : 只对指定范围内的第一个匹配项进行替换。
g : 对指定范围内的所有匹配项进行替换。
c : 在替换前请求用户确认。
e : 忽略执行过程中的错误。
注意:上面的所有flags都可以组合起来使用,比如 gc 表示对指定范围内的
所有匹配项进行替换,并且在每一次替换之前都会请用户确认。