サイト内のSharePointリスト内の特定のファイルタイプを検索し、ファイル名をlistviewに表示するC#コードを記述しました。 このコードはC#のWindowsアプリケーションではうまく動作しますが、C#DLLにコンパイルされ、Delphi2007アプリケーションから呼び出されると、ClientContext.ExecuteQuery()の最初の呼び出しにヒットするとクラッシュします。例外またはエラーメッセージはありません.Delphiアプリケーションは実行を停止します。SharePoint ClientContext.ExecuteQueryはC#アプリケーションで動作しますが、DLLでクラッシュします
本当に奇妙な部分は、私のDelphiテストアプリケーションにはWebブラウザコンポーネントがあり、それを使ってサイトのトップレベルのリストに移動すると、DLLは正常に動作します。
なぜ最初にサイトにログオンしていないと、最初のExecuteQuery呼び出しがDLLで失敗するのですか?
これは、C#コードである:
public void ListFiles()
{
string LContains = "<Contains><FieldRef Name='FileLeafRef'/> <Value Type ='Text'>{0}</Value></Contains>";
string LNotEqual = "<Contains><FieldRef Name='FileLeafRef'/><Value Type ='Text'>{0}</Value></Contains>";
string LWhereQuery = "";
switch (comboFileType.SelectedIndex)
{
case 0: LWhereQuery = string.Format(LContains, ".DOC"); break;
case 1: LWhereQuery = string.Format(LContains, ".PDF"); break;
case 2: LWhereQuery = string.Format(LNotEqual, "xxxx"); break;
}
Uri LUri = new Uri(SharePointURL);
using (SP.ClientContext LContext = new SP.ClientContext(SharePointURL))
{
System.Net.CredentialCache cc = new System.Net.CredentialCache();
if (!string.IsNullOrEmpty(Domain))
cc.Add(LUri, AuthenticationType, new System.Net.NetworkCredential(UserName, Password, Domain));
else
cc.Add(LUri, AuthenticationType, new System.Net.NetworkCredential(UserName, Password));
LContext.Credentials = cc;
LContext.AuthenticationMode = SP.ClientAuthenticationMode.Default;
var LWeb = LContext.Web;
lvItems.BeginUpdate();
try
{
try
{
SP.List LList = LWeb.Lists.GetByTitle(DefaultListName);
SP.CamlQuery LQuery = new SP.CamlQuery();
LQuery.ViewXml = "<View Scope='RecursiveAll'><Query><Where>"
+ LWhereQuery
+ "</Where></Query><RowLimit> 30 </RowLimit></View>";
SP.ListItemCollection LItems = LList.GetItems(LQuery);
LContext.Load(LItems);
LContext.ExecuteQuery(); **<<<< Crash happens here**
foreach (SP.ListItem LItem in LItems)
{
SP.File LFile = LItem.File;
LContext.Load(LFile);
LContext.ExecuteQuery();
var LViewItem = new ListViewItem();
try { LViewItem.Text = LFile.Name; }
catch { LViewItem.Text = "!Error"; }
try { LViewItem.SubItems.Add(LFile.TimeLastModified.ToString()); }
catch { LViewItem.SubItems.Add("!Error"); }
if (LFile.CheckOutType != Microsoft.SharePoint.Client.CheckOutType.None)
{
try { LViewItem.SubItems.Add(LFile.CheckedOutByUser.LoginName); }
catch { LViewItem.SubItems.Add("!Error"); }
}
else
LViewItem.SubItems.Add("Not checked out.");
try { LViewItem.Tag = LFile.ServerRelativeUrl; }
catch { LViewItem.Tag = "!Error"; }
lvItems.Items.Add(LViewItem);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex);
}
}
finally
{
lvItems.EndUpdate();
}
}
コードはDLLでダイアログフォームの.csファイルです。フォームは必要に応じて表示され、ボタンをクリックするとクラッシュが発生します。
すべての文字列のparamsなどを(テキストファイルに書き込むことで)チェックするためにいくつかのデバッグコードを入れました。すべてOKです。
「スタートアップ外部プログラム」としてD2007アプリケーションを指定してVSからDLLをデバッグしようとしましたが、動作するブレークポイントを取得できず、クラッシュしたポイントで次のように表示されます。未処理例外 'System .StackOverflowException 'Microsoft.SharePoint.Client.Runtime.dllで発生しましたと私は無限の再帰呼び出しがあることを示唆していますが、すでに述べたように、コードは、サイトに既にログインし、トップレベルの一覧私はそれが再帰呼び出しだとは思わない。
更新:DelphiのexeファイルをDLLと同じディレクトリにコピーすることで、デバッグができます。
私はExceptionHandlingScopeの使用を試みましたが、助けにはなりませんでした。これは、クラッシュしたときに、それがどのように見えるかです:
スコープは、例外を持っていないとにErrorMessageは空白です。私はスコープの中に何が入っているのかを何度も試してみましたが、役に立たなかったのです。
コードブロック全体がtry..catch内にあり、私はExecuteQuery行をそれ自身のtry..catchでラップしようとしましたが、何もキャッチしません。アプリが続行するたびにクラッシュする。
ウェブをロードする前に実行クエリを入れてみましたが、それでもクラッシュしました。
資格情報とは何か関係がありますか?意図的に間違ったユーザー名を入力すると、丁寧な「401 Unauthorized」バックとクラッシュは発生しません。すでにログインしていてもクラッシュしませんか?
あなたの問題は例外処理である可能性があります。効果的にDLL/Delphi境界を越えて例外を渡そうとしている可能性はありますか?これは絶対に禁止されており、スタックオーバーフローは、例外を生成する例外を生成した例外の結果である可能性があります。非ゼロ値を返す例外トラップを使用して、dll内のすべてのインタフェース呼び出しをラップする必要があります。私はDelphiでそれを行う方法を知っていますが、C#ではなく、悲しいことです。 – Dsm
@Dsm:返信いただきありがとうございます。メソッドのほとんどはTry..ExceptのC#に相当するTry..Catchブロック内にあります。私はコード内のすべての例外を処理しています(私は思う!)、必要なときにcom境界を越えて文字列エラーメッセージを渡します。スタックオーバーフローエラーは、MSPクライアントランタイムライブラリに言及しているので、C#コードとそのライブラリの間に問題があると示唆していますか?私はフォーム上に何かを閉じ込めていない可能性がありますので、もう一度見ていきます。 – Mick
はおそらく最も高レベルでキャッチオールを行うだけでなく、個々のキャッチオールをキャッチしようとするのが最も安全です。そのため、ListFilesをエクスポートすると、たとえ例外が生成されるべきではないとしても、コード全体(初期文字列の割り当てさえ)でもtry-catchが必要です。それは単なる安全上の第一のものです。 – Dsm