Details needed on creating a custom conflict resolver using a COM based approach

Answered Details needed on creating a custom conflict resolver using a COM based approach

  • Tuesday, December 04, 2012 5:01 PM
     
      Has Code

    The directions that I am trying to follow are here and they're duplicated below: 

        http://www.replicationanswers.com/CustomResolver.asp

    Directions:

    • Open a Visual Studio .NET 2003 Command Prompt
    •  tlbimp "c:\Program Files\Microsoft SQL Server\80\COM\replrec.dll" /OUT:SQLResolver_import.dll
    • ildasm "SQLResolver_import.dll" /OUT=SQLResolver.il
    • Change line "[out] object&  marshal( struct) pvBuffer" for the methods GetSourceColumnValue, GetDestinationColumnValue, and SetColumn to "[out] int32 pvBuffer"
    • ilasm SQLResolver.il /OUT=SQLResolver.dll /dll
    • Create a new .NET Windows Control Library project
    • Remove the wizard generated control
    • Use "Add New Item..." to add a new COM class
    • Add reference to SQLResolver.dll created in step #5

    Step 1a. cd C:\Program*Files*x86*\Microsoft*Visual*Studio*11.0\VC\

    Step 1b. execute vcvarsall.bat

    Step 2a. cd c:\Users\Current_User\Desktop\

    Step 2b. Output messages executing tlbimp "C:\PROGRA~1\MICROS~3\100\com\replrec.dll" /out:SQLResolver_import.dll

    Microsoft (R) .NET Framework Type Library to Assembly Converter 4.0.30319.17929
    Copyright (C) Microsoft Corporation.  All rights reserved.

    TlbImp : warning TI3002 : Importing a type library into a platform agnostic assembly.  This can cause errors if the type library is not truly platform agnostic.

    TlbImp : warning TI3015 : At least one of the arguments for 'SQLResolver_import.
    IReplRowChange.GetSourceColumnValue2' cannot be marshaled by the runtime marshaler.  Such arguments will therefore be passed as a pointer and may require unsafe code to manipulate.

    TlbImp : warning TI3015 : At least one of the arguments for 'SQLResolver_import.
    IReplRowChange.GetDestinationColumnValue2' cannot be marshaled by the runtime marshaler.  Such arguments will therefore be passed as a pointer and may require unsafe code to manipulate.

    TlbImp : warning TI3015 : At least one of the arguments for 'SQLResolver_import.
    IReplRowChange.SetColumn2' cannot be marshaled by the runtime marshaler.  Such arguments will therefore be passed as a pointer and may require unsafe code to manipulate.

    TlbImp : warning TI3015 : At least one of the arguments for 'SQLResolver_import.
    CLRBusinessLogicModuleClass.GetSourceColumnValue2' cannot be marshaled by the runtime marshaler.  Such arguments will therefore be passed as a pointer and may require unsafe code to manipulate.

    TlbImp : warning TI3015 : At least one of the arguments for 'SQLResolver_import.
    CLRBusinessLogicModuleClass.GetDestinationColumnValue2' cannot be marshaled by the runtime marshaler.  Such arguments will therefore be passed as a pointer and may require unsafe code to manipulate.

    TlbImp : warning TI3015 : At least one of the arguments for 'SQLResolver_import.
    CLRBusinessLogicModuleClass.SetColumn2' cannot be marshaled by the runtime marshaler.  Such arguments will therefore be passed as a pointer and may require unsafe code to manipulate.

    TlbImp : Type library imported to c:\Users\Current_User\Desktop\SQLResolver_import.dll

    Step 3.

    • Change line "[out] object&  marshal( struct) pvBuffer" for the methods GetSourceColumnValue, GetDestinationColumnValue, and SetColumn to "[out] int32 pvBuffer"

    There are no methods GetSourceColumnValue, GetDestinationColumnValue, and SetColumn. For example, the file SQLResolver.il has the below. Question: Should I change all of the below methods that refer to "[out] object&  marshal( struct) pvBuffer"?

    Some of the file's contents are:

      .method public hidebysig newslot abstract virtual 
              instance void  RemoteGetSourceColumnValue(uint32 ColumnId,
                                                        [out] object&  marshal( struct) pvBuffer,
                                                        [in] uint32 cbBufferMax,
                                                        [out] uint32& pcbBufferActual) runtime managed internalcall
      {
      } // end of method IReplRowChange::RemoteGetSourceColumnValue
      .method public hidebysig newslot abstract virtual 
              instance void  GetSourceColumnValue2(uint32 ColumnId,
                                                   [out] native int ppBuffer,
                                                   [in] uint32 cbBufferMax,
                                                   [out] uint32& pcbBufferActual) runtime managed internalcall
      {
      } // end of method IReplRowChange::GetSourceColumnValue2
      .method public hidebysig newslot abstract virtual 
              instance void  RemoteGetSourceColumnValueWithStatus(uint32 ColumnId,
                                                                  [out] object&  marshal( struct) pvBuffer,
                                                                  [in] uint32 cbBufferMax,
                                                                  [out] uint32& pcbBufferActual,
                                                                  [out] uint32& pDBStatus) runtime managed internalcall
      {
      } // end of method IReplRowChange::RemoteGetSourceColumnValueWithStatus
      .method public hidebysig newslot virtual 
              instance void  RemoteGetSourceColumnValue(uint32 ColumnId,
                                                        [out] object&  marshal( struct) pvBuffer,
                                                        [in] uint32 cbBufferMax,
                                                        [out] uint32& pcbBufferActual) runtime managed internalcall
      {
        .override SQLResolver_import.IReplRowChange::RemoteGetSourceColumnValue
      } // end of method CLRBusinessLogicModuleClass::RemoteGetSourceColumnValue
      .method public hidebysig newslot virtual 
              instance void  GetSourceColumnValue2(uint32 ColumnId,
                                                   [out] native int ppBuffer,
                                                   [in] uint32 cbBufferMax,
                                                   [out] uint32& pcbBufferActual) runtime managed internalcall
      {
        .override SQLResolver_import.IReplRowChange::GetSourceColumnValue2
      } // end of method CLRBusinessLogicModuleClass::GetSourceColumnValue2
      .method public hidebysig newslot virtual 
              instance void  RemoteGetSourceColumnValueWithStatus(uint32 ColumnId,
                                                                  [out] object&  marshal( struct) pvBuffer,
                                                                  [in] uint32 cbBufferMax,
                                                                  [out] uint32& pcbBufferActual,
                                                                  [out] uint32& pDBStatus) runtime managed internalcall
      {
        .override SQLResolver_import.IReplRowChange::RemoteGetSourceColumnValueWithStatus
      } // end of method CLRBusinessLogicModuleClass::RemoteGetSourceColumnValueWithStatus


    Below is the only SetColumn method in the file. It doesn't have the "out" parameter! What should I do with this?


      .method public hidebysig newslot abstract virtual 
              instance void  RemoteSetColumn(uint32 ColumnId,
                                             [in] object&  marshal( struct) pvBuffer,
                                             uint32 cbBuffer) runtime managed internalcall
      {
      } // end of method IReplRowChange::RemoteSetColumn

All Replies

  • Tuesday, December 04, 2012 5:07 PM
    Moderator
     
     Answered
    Yes, change all method parameters [out] object&  marshal( struct) pvBuffer to [out] int32 pvBuffer.

    Brandon Williams (blog | linkedin)

  • Tuesday, December 04, 2012 5:09 PM
    Moderator
     
     Answered
    Also, as we can see, there have been some changes to the API since this document was written:  Creating Merge Replication Custom Conflict Resolvers Using Visual Basic.

    Brandon Williams (blog | linkedin)

  • Tuesday, December 04, 2012 5:12 PM
     
     

    What about [in] object&  marshal( struct) pvBuffer.

    Thanks,

  • Tuesday, December 04, 2012 5:15 PM
    Moderator
     
     Answered
    Yes, make the change there to [in] int32 pvBuffer.

    Brandon Williams (blog | linkedin)

  • Tuesday, December 04, 2012 5:26 PM
     
     

    What about the numerous other references to the marshal class such as below. Do I leave them all alone!

      .method public hidebysig newslot abstract virtual
              instance void  RemoteReconcile([in] class SQLResolver_import.IReplRowChange  marshal( interface ) pRowChange,
                                             uint32 dwFlags,
                                             [in] class SQLResolver_import.IReplRowChange  marshal( interface ) pvReserved) runtime managed internalcall
      {
      } // end of method ICustomResolver::RemoteReconcile

      .method public hidebysig newslot abstract virtual
              instance void  GetResolverProcedureName([out] class [mscorlib]System.Text.StringBuilder  marshal( lpwstr) pResolverProcedureName,
                                                      uint32 cbResolverProcedureName) runtime managed internalcall
      {
      } // end of method IReplRowChange::GetResolverProcedureName

      .method public hidebysig newslot abstract virtual
              instance void  GetColumnName(uint32 ColumnId,
                                           [out] class [mscorlib]System.Text.StringBuilder  marshal( lpwstr) pColumnName,
                                           uint32 cbColumnName) runtime managed internalcall
      {
      } // end of method IReplRowChange::GetColumnName


      .method public hidebysig newslot abstract virtual
              instance void  LogConflict([in] int32 bLogSourceConflict,
                                         [in] valuetype SQLResolver_import.REPOLE_CONFLICT_TYPE ConflictType,
                                         [in] int32 bOnlyLogIfUpdater,
                                         [in][opt] string  marshal( bstr) pszConflictMessage,
                                         [in][opt] int32 bLogConflictOnUpload) runtime managed internalcall
      {
        .param [2]
        .custom instance void [mscorlib]System.Runtime.InteropServices.ComAliasNameAttribute::.ctor(string) = ( 01 00 27 53 51 4C 52 65 73 6F 6C 76 65 72 5F 69   // ..'SQLResolver_i
                                                                                                                6D 70 6F 72 74 2E 52 45 50 4F 4C 45 5F 43 4F 4E   // mport.REPOLE_CON
                                                                                                                46 4C 49 43 54 5F 54 59 50 45 00 00 )             // FLICT_TYPE..
        .param [4] = "0"
        .param [5] = int32(0x00000000)
      } // end of method IReplRowChange::LogConflict


  • Tuesday, December 04, 2012 5:35 PM
    Moderator
     
     Answered

    Leave them alone.  At this point I believe we only need to be concerned about changing the buffer parameters of the methods that are defined to be the address of an object, which we have already done.


    Brandon Williams (blog | linkedin)