現在、Outlookアドレスブック全体をインポートする必要のあるプログラムを作成しています。プログラムはC++(gcc(MinGW)でコンパイル)で書かれており、ActiveXを使用してOutlookに接続しています。
これが私がすることです:
- Outlook.Applicationのインスタンスを作成します
- 現在のセッションを取得する
- アドレスリストを取得する
- AddressListsの各AddressListについて:AddressEntriesを取得します
- AddressEntriesの各AddressEntryについて:それがContactItem、ExchangeUser、またはその他のものであるかどうかを判別します
- ContactItemの場合:次のプロパティを読み取ります:FirstName、LastName、MailingAddressStreet、MailingAddressPostOfficeBox、MailingAddressPostalCode、MailingAddressCity、CompanyName、Department、JobTitle、PrimaryTelephoneNumber、OtherTelephoneNumber、BusinessFaxNumber、Email1Address
- ExchangeUserの場合:次のプロパティを読み取ります:FirstName、LastName、StreetAddress、PostalCode、City、CompanyName、Department、JobTitle、BusinessTelephoneNumber、MobileTelephoneNumber、Address
- それがさらに別のタイプのAddressEntryである場合は、無視してください
名簿に連絡先が数人しかない限り、これは魅力のように機能します。しかし今、私はそれを大企業で試運転しています。そこでは、名簿に約500の連絡先(ContactItemsとExchangeUsersの両方)があり、22の異なるAddressListに分割されています。
最大のAddressList(180個のAddressEntries、すべてのExchangeUsersを含む)の読み取り中に、OutlookのActiveXコンポーネントが突然不明なエラーを返します(IDispatch-> Invokeの戻り値は0xFFFFFFFFです)。これは通常、105番目と115番目のAddressEntryの間のどこかであり、通常はMobileTelephoneNumberプロパティの読み取り中です(ただし、コメントアウトすると、別の呼び出しで失敗します。
私が間違っている可能性のあるアイデアはありますか?大量の連続通話と関係があるような気がします。たぶん、すべての呼び出しの後に私がしなければならないある種のクリーンアップがありますか?
とにかく、どんな助けでも大歓迎です!
よろしく、ldx
編集:コード(簡潔にするためにヘッダーファイルを省略)
1.アプリケーションクラス
Contact * MSOutlookContactSource::ToContact(SP<ContactUser> contactUser) const
{
Contact * c = new Contact;
c->setFirstName(contactUser->GetFirstName())
.setLastName(contactUser->GetLastName())
.setStreet(contactUser->GetMailingAddressStreet())
.setStreetNr(contactUser->GetMailingAddressPostOfficeBox())
.setZip(contactUser->GetMailingAddressPostalCode())
.setCity(contactUser->GetMailingAddressCity())
.setCompany(contactUser->GetCompanyName())
.setDepartment(contactUser->GetDepartment())
.setFunction(contactUser->GetJobTitle())
.setTel1(contactUser->GetPrimaryTelephoneNumber())
.setTel2(contactUser->GetOtherTelephoneNumber())
.setFax(contactUser->GetBusinessFaxNumber())
.setEmail(contactUser->GetEmail1Address());
return c;
}
//----------------------------------------------------------------------
Contact * MSOutlookContactSource::ToContact(SP<ExchangeUser> exchangeUser) const
{
Contact * c = new Contact;
c->setFirstName(exchangeUser->GetFirstName())
.setLastName(exchangeUser->GetLastName())
.setStreet(exchangeUser->GetStreetAddress())
.setZip(exchangeUser->GetPostalCode())
.setCity(exchangeUser->GetCity())
.setCompany(exchangeUser->GetCompanyName())
.setDepartment(exchangeUser->GetDepartment())
.setFunction(exchangeUser->GetJobTitle())
.setTel1(exchangeUser->GetBusinessTelephoneNumber())
.setTel2(exchangeUser->GetMobileTelephoneNumber())
.setEmail(exchangeUser->GetAddress());
return c;
}
//----------------------------------------------------------------------
vector<Contact *> MSOutlookContactSource::GetAllContacts() const
{
LOG << "GetAllContacts" << endl;
ActiveX::Initialize();
vector<Contact *> retval;
SP<Application> outlookApplication(Application::Create());
SP<Namespace> session(outlookApplication->GetSession());
SP<AddressLists> addressLists(session->GetAddressLists());
long numAddressLists = addressLists->GetCount();
LOG << "Found " << numAddressLists << " addressLists" << endl;
for (long idxAddressLists = 1; idxAddressLists <= numAddressLists; ++idxAddressLists)
{
LOG << "Fetching addressList " << idxAddressLists << endl;
SP<AddressList> addressList(addressLists->Item(idxAddressLists));
SP<AddressEntries> addressEntries(addressList->GetAddressEntries());
long numAddressEntries = addressEntries->GetCount();
LOG << "Found " << numAddressEntries << " addressEntries" << endl;
for (long idxAddressEntries = 1; idxAddressEntries <= numAddressEntries; ++idxAddressEntries)
{
LOG << "Fetching addressEntry " << idxAddressEntries << endl;
SP<AddressEntry> addressEntry(addressEntries->Item(idxAddressEntries));
SP<ContactUser> contactUser(addressEntry->GetContact());
if (contactUser->IsNull())
{
SP<ExchangeUser> exchangeUser(addressEntry->GetExchangeUser());
if (!exchangeUser->IsNull())
{
LOG << "It's an ExchangeUser" << endl;
retval.push_back(ToContact(exchangeUser));
}
else
LOG << "I don't know what it is => skipping" << endl;
}
else
{
LOG << "It's a ContactUser" << endl;
retval.push_back(ToContact(contactUser));
}
}
}
ActiveX::Uninitialize();
unsigned num_found = retval.size();
LOG << "Found " << num_found << " contacts" << endl;
return retval;
}
//----------------------------------------------------------------------
2.ドメインオブジェクト(例)。他のドメインオブジェクトも同様に実装されます
ExchangeUser::ExchangeUser() :
ActiveXProxy(NULL)
{
}
//----------------------------------------------------------------------
ExchangeUser::ExchangeUser(IDispatch * parent) :
ActiveXProxy(parent)
{
}
//----------------------------------------------------------------------
ExchangeUser::~ExchangeUser()
{
}
//----------------------------------------------------------------------
ExchangeUser::ExchangeUser(const ExchangeUser & to_copy) :
ActiveXProxy(to_copy)
{
}
//----------------------------------------------------------------------
ExchangeUser & ExchangeUser::operator=(const ExchangeUser & to_copy)
{
if (&to_copy != this)
{
*((ActiveXProxy *)this) = to_copy;
}
return *this;
}
//----------------------------------------------------------------------
bool ExchangeUser::IsNull()
{
return _parent == NULL;
}
//----------------------------------------------------------------------
string ExchangeUser::GetFirstName()
{
wstring wstr(ActiveX::GetProperty(_parent, L"FirstName", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetLastName()
{
wstring wstr(ActiveX::GetProperty(_parent, L"LastName", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetStreetAddress()
{
wstring wstr(ActiveX::GetProperty(_parent, L"StreetAddress", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetPostalCode()
{
wstring wstr(ActiveX::GetProperty(_parent, L"PostalCode", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetCity()
{
wstring wstr(ActiveX::GetProperty(_parent, L"City", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetCompanyName()
{
wstring wstr(ActiveX::GetProperty(_parent, L"CompanyName", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetDepartment()
{
wstring wstr(ActiveX::GetProperty(_parent, L"Department", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetJobTitle()
{
wstring wstr(ActiveX::GetProperty(_parent, L"JobTitle", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetBusinessTelephoneNumber()
{
wstring wstr(ActiveX::GetProperty(_parent, L"BusinessTelephoneNumber", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetMobileTelephoneNumber()
{
wstring wstr(ActiveX::GetProperty(_parent, L"MobileTelephoneNumber", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
string ExchangeUser::GetAddress()
{
wstring wstr(ActiveX::GetProperty(_parent, L"Address", 0).bstrVal);
string str(wstr.size(), ' ');
copy(wstr.begin(), wstr.end(), str.begin());
return str;
}
//----------------------------------------------------------------------
3. ActiveXProxy基本クラス(_parentはIDispatch *)
ActiveXProxy::ActiveXProxy() :
_parent(NULL)
{
}
//----------------------------------------------------------------------
ActiveXProxy::ActiveXProxy(IDispatch * parent) :
_parent(parent)
{
}
//----------------------------------------------------------------------
ActiveXProxy::~ActiveXProxy()
{
if (_parent != NULL)
{
_parent->Release();
_parent = NULL;
}
}
//----------------------------------------------------------------------
ActiveXProxy::ActiveXProxy(const ActiveXProxy & to_copy) :
_parent(to_copy._parent)
{
}
//----------------------------------------------------------------------
ActiveXProxy & ActiveXProxy::operator=(const ActiveXProxy & to_copy)
{
if (&to_copy != this)
{
_parent = to_copy._parent;
}
return *this;
}
//----------------------------------------------------------------------
4.ActiveXユーティリティクラス
map<HRESULT, string> ActiveX::_errorTranslations;
unsigned ActiveX::_numInits = 0;
//----------------------------------------------------------------------
void ActiveX::Initialize()
{
if (_numInits == 0)
{
CoInitialize(NULL);
_errorTranslations[DISP_E_BADPARAMCOUNT] = "DISP_E_BADPARAMCOUNT";
_errorTranslations[DISP_E_BADVARTYPE] = "DISP_E_BADVARTYPE";
_errorTranslations[DISP_E_EXCEPTION] = "DISP_E_EXCEPTION";
_errorTranslations[DISP_E_MEMBERNOTFOUND] = "DISP_E_MEMBERNOTFOUND";
_errorTranslations[DISP_E_NONAMEDARGS] = "DISP_E_NONAMEDARGS";
_errorTranslations[DISP_E_OVERFLOW] = "DISP_E_OVERFLOW";
_errorTranslations[DISP_E_PARAMNOTFOUND] = "DISP_E_PARAMNOTFOUND";
_errorTranslations[DISP_E_TYPEMISMATCH] = "DISP_E_TYPEMISMATCH";
_errorTranslations[DISP_E_UNKNOWNINTERFACE] = "DISP_E_UNKNOWNINTERFACE";
_errorTranslations[DISP_E_UNKNOWNLCID ] = "DISP_E_UNKNOWNLCID ";
_errorTranslations[DISP_E_PARAMNOTOPTIONAL] = "DISP_E_PARAMNOTOPTIONAL";
}
_numInits++;
}
//----------------------------------------------------------------------
void ActiveX::Uninitialize()
{
if (_numInits > 0)
{
_numInits--;
if (_numInits == 0)
CoUninitialize();
}
}
//----------------------------------------------------------------------
VARIANT ActiveX::GetProperty(IDispatch * from, LPOLESTR olePropertyName, int cArgs...)
{
va_list marker;
va_start(marker, cArgs);
VARIANT *pArgs = new VARIANT[cArgs+1];
char name[256];
WideCharToMultiByte(CP_ACP, 0, olePropertyName, -1, name, 256, NULL, NULL);
string propertyName(name);
DISPID dispId;
HRESULT hr = from->GetIDsOfNames(IID_NULL, &olePropertyName, 1, LOCALE_USER_DEFAULT, &dispId);
if (SUCCEEDED(hr))
{
// Extract arguments...
for(int i=0; i<cArgs; i++)
pArgs[i] = va_arg(marker, VARIANT);
// Build DISPPARAMS
DISPPARAMS dispParams = { NULL, NULL, 0, 0 };
dispParams.cArgs = cArgs;
dispParams.rgvarg = pArgs;
EXCEPINFO excepInfo;
VARIANT vProperty;
hr = from->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &vProperty, &excepInfo, NULL);
if (SUCCEEDED(hr))
{
va_end(marker);
delete [] pArgs;
return vProperty;
}
else
{
va_end(marker);
delete [] pArgs;
stringstream errorMessage;
errorMessage << "Failed to Invoke property-get on " << propertyName << " (" << hr << " - " << TranslateError(hr);
if (hr == DISP_E_EXCEPTION)
errorMessage << " exception: " << excepInfo.wCode << " - " << excepInfo.bstrDescription;
errorMessage << " )";
throw ActiveXException(errorMessage.str());
}
}
else
{
va_end(marker);
delete [] pArgs;
throw ActiveXException(string("Failed to get DISPID of property ") + propertyName);
}
}
//----------------------------------------------------------------------
VARIANT ActiveX::CallMethod(IDispatch * on, LPOLESTR oleMethodName, int cArgs...)
{
va_list marker;
va_start(marker, cArgs);
VARIANT *pArgs = new VARIANT[cArgs+1];
char name[256];
WideCharToMultiByte(CP_ACP, 0, oleMethodName, -1, name, 256, NULL, NULL);
string methodName(name);
DISPID dispId;
HRESULT hr = on->GetIDsOfNames(IID_NULL, &oleMethodName, 1, LOCALE_USER_DEFAULT, &dispId);
if (SUCCEEDED(hr))
{
// Extract arguments...
for(int i=0; i<cArgs; i++)
pArgs[i] = va_arg(marker, VARIANT);
// Build DISPPARAMS
DISPPARAMS dp = { NULL, NULL, 0, 0 };
dp.cArgs = cArgs;
dp.rgvarg = pArgs;
// Make the call!
EXCEPINFO excepInfo;
VARIANT result;
hr = on->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp, &result, &excepInfo, NULL);
if(SUCCEEDED(hr))
return result;
else
{
va_end(marker);
delete [] pArgs;
stringstream errorMessage;
errorMessage << "Failed to call method " << methodName << " (" << hr << " - " << TranslateError(hr);
if (hr == DISP_E_EXCEPTION)
errorMessage << " exception: " << excepInfo.wCode << " - " << excepInfo.bstrDescription;
errorMessage << " )";
throw ActiveXException(errorMessage.str());
}
}
else
{
va_end(marker);
delete [] pArgs;
throw ActiveXException(string("Failed to get DISPID of method ") + methodName);
}
}
//----------------------------------------------------------------------
string ActiveX::TranslateError(HRESULT error)
{
return _errorTranslations[error];
}
//----------------------------------------------------------------------
ActiveXは純粋な静的クラスです
編集2:これはC++関連の問題ではないようです。リソースの解放が問題にならないようにしたかったのです。だから私はVBSで私のコードを複製しました(私を撃ちます):
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FileExists("out.log") Then
objFSO.CreateTextFile("out.log")
End If
Set objLog = objFSO.OpenTextFile("out.log", 2, True)
Set objOutlook = CreateObject("Outlook.Application")
Set objSession = objOutlook.Session
Set objAddressLists = objSession.AddressLists
objLog.WriteLine("--- Found " + CStr(objAddressLists.Count) + " AddressLists")
For i = 1 To objAddressLists.Count
objLog.WriteLine("--- AddressList " + CStr(i))
Set objAddressList = objAddressLists.Item(i)
objLog.WriteLine("+++ AddressListName = " + objAddressList.Name)
Set objAddressEntries = objAddressList.AddressEntries
objLog.WriteLine("--- AddressList has " + CStr(objAddressEntries.Count) + " AddressEntries")
For j = 1 To objAddressEntries.Count
objLog.WriteLine("--- AddressEntry " + CStr(i) + "." + CStr(j))
Set objAddressEntry = objAddressEntries.Item(j)
If objAddressEntry.AddressEntryUserType = olExchangeUserAddressEntry Then
Set objExchangeUser = objAddressEntry.GetExchangeUser()
objLog.WriteLine("Exchangeuser: " + _
objExchangeUser.FirstName + "|" + _
objExchangeUser.LastName + "|" + _
objExchangeUser.StreetAddress + "|" + _
objExchangeUser.PostalCode + "|" + _
objExchangeUser.City + "|" + _
objExchangeUser.CompanyName + "|" + _
objExchangeUser.Department + "|" + _
objExchangeUser.JobTitle + "|" + _
objExchangeUser.BusinessTelephoneNumber + "|" + _
objExchangeUser.MobileTelephoneNumber + "|" + _
objExchangeUser.Address)
Set objExchangeUser = Nothing
ElseIf objAddressEntry.AddressEntryUserType = olOutlookContactAddressEntry Then
Set objContact = objAddressEntry.GetContact()
objLog.WriteLine("Contactuser: " + _
objContact.FirstName + "|" + _
objContact.LastName + "|" + _
objContact.MailingAddressStreet + "|" + _
objContact.MailingAddressPostOfficeBox + "|" + _
objContact.MailingAddressPostalCode + "|" + _
objContact.MailingAddressCity + "|" + _
objContact.CompanyName + "|" + _
objContact.Department + "|" + _
objContact.JobTitle + "|" + _
objContact.PrimaryTelephoneNumber + "|" + _
objContact.OtherTelephoneNumber + "|" + _
objContact.BusinessFaxNumber + "|" + _
objContact.Email1Address)
Set objContact = Nothing
End If
Set objAddressEntry = Nothing
Next
Set objAddressEntries = Nothing
Set objAddressList = Nothing
Next
objTextFile.Close
MsgBox "Done"
そして、何を推測します:私もエラーが発生します!! VBSだけが私にいくつかの追加情報を与えるようです:時々私は得る:
エラー:サーバーが例外をスローしました コード:80010105 ソース:(null)
そして時々私は得る:
エラー:リモートプロシージャコールが失敗しました コード:800706BE ソース:(null)
また:エラーの後、Outlookは完全にクラッシュします:-|
ヘルプ!