3

ComImport を使用して Windows 検索を呼び出すコンソール アプリがあります。これはデバッグ モードでは正常に機能しますが、リリース モードではコンソール アプリケーションがクラッシュします。何が問題なのですか?

[ComImport]
    [Guid("9DAA54E8-CD95-4107-8E7F-BA3F24732D95")]
    [ClassInterface(ClassInterfaceType.None)]
    [TypeLibType(TypeLibTypeFlags.FCanCreate)]
    public class WordBreaker : IWordBreaker
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        public virtual extern bool Init([In] bool query, [In] uint maxTokenSize);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        public virtual extern void BreakText([In, MarshalAs(UnmanagedType.LPStruct)] TEXT_SOURCE textSource,
            [In] IWordSink wordSink, [In] IPhraseSink phraseSink);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        public virtual extern void ComposePhrase([In, MarshalAs(UnmanagedType.LPWStr)] string noun, [In] uint nounLen,
            [In, MarshalAs(UnmanagedType.LPWStr)] string modifier, [In] uint modifierLen,
            [In] uint attachmentType, [Out] out IntPtr phrase, [In, Out] ref uint phraseLen);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        public virtual extern IntPtr GetLicenseToUse();
    }

WordBreaker.BreakText 関数にアクセスしているときに、リリース モードでコードが失敗します。

以下に示すように、コードで使用されています

if (!string.IsNullOrWhiteSpace(text))
                try
                {
                    IWordBreaker breaker = new WordBreaker();
                    bool reqLicense = breaker.Init(query, 256);
                    if (reqLicense)
                    {
                        IntPtr lic = breaker.GetLicenseToUse();
                        string licText = Marshal.PtrToStringUni(lic);
                    }
                    TEXT_SOURCE source = new TEXT_SOURCE();
                    source.fillTextBuffer = FillTextBuffer;
                    source.buffer = text;
                    source.cur = 0;
                    source.end = (uint)(text.Length);
                    breaker.BreakText(source, new WordSink(result), null);
                }
                catch (Exception ex)
                {
                    Console.Out.WriteLine(ex.ToString());
                    //log4net.LogManager.GetLogger(typeof(WindowsIntegration)).Error("BreakText", ex);
                }
            var resultWithoutNoise = NoiseWord.Remove(result);
            return resultWithoutNoise;
        }

アプリがクラッシュする前に、関数がbreaker.BreakTextBreakText度も (500 ~ 7000 回) 呼び出されます。

クラッシュダンプには、例外情報について次のように記載 The thread tried to read from or write to a virtual address for which it does not have the appropriate access. されています。コードでスレッドを使用していません。

4

3 に答える 3

1

これは、ガベージ コレクターがテキストを別の場所に移動しているため、source.buffer に記録されているアドレスが無効になっている場合のようです。TEXT_SOURCE を宣言するソースが含まれていないため、コメントできません。しかし、BreakText の宣言は正しくありません。そこでは MarshalAs(UnmanagedType.LPStruct) を使用しないでください。UnmanagedType.LPStruct がサポートされるのは、System.Guid 値の型を特別なレベルの間接化を持つアンマネージド GUID として扱う、1 つの特定のケースのみです。http://blogs.msdn.com/b/adam_nathan/archive/2003/04/23/56635.aspxおよび構造体へのポインターとして構造体をマーシャリングする方法を参照してください。.

于 2013-09-09T23:27:34.340 に答える
1

コードには、エラーが参照しているスレッドが少なくとも 1 つ必要です。クラッシュの種類については、基本的にアクセス違反であり、null ポインター/オブジェクト参照 (ネイティブ コード内) またはバッファー オーバーランのいずれかです。どのような値かを確認します。ストリング。失敗した時点で渡している長さなど。

于 2011-06-29T11:49:41.383 に答える
0

問題を再現できず、リリースでしか再現できない場合は、ログを追加して問題を絞り込むことを強くお勧めします。

問題を絞り込んだら、上記の投稿を編集して、クラッシュに関するより詳細な情報を含めます。

于 2011-06-29T11:43:06.083 に答える