C# SetupCopyOEMInf安装驱动并返回DestinationInfFileNameComponent

最近用C#写安装usb驱动,必须得调用API SetupCopyOEMInf:

BOOL WINAPI SetupCopyOEMInf(
  _In_       PCTSTR SourceInfFileName,
  _In_       PCTSTR OEMSourceMediaLocation,
  _In_       DWORD OEMSourceMediaType,
  _In_       DWORD CopyStyle,
  _Out_opt_  PTSTR DestinationInfFileName,
  _In_       DWORD DestinationInfFileNameSize,
  _Out_opt_  PDWORD RequiredSize,
  _Out_opt_  PTSTR DestinationInfFileNameComponent
);

于是在C#里这么写了:

        [DllImport("setupapi.dll", SetLastError = true)]
        private static extern bool SetupCopyOEMInf(

            string SourceInfFileName,
            string OEMSourceMediaLocation,
            OemSourceMediaType OEMSourceMediaType,
            OemCopyStyle CopyStyle,
            out string DestinationInfFileName,
            int DestinationInfFileNameSize,
            int RequiredSize,
            out string DestinationInfFileNameComponent

        );

其中DestinationInfFileName代表驱动成功安装后,inf文件在C:\Windows\inf目录下的绝对路径,这个inf文件名字和原inf文件不一样,但是内容是一模一样的,不知道为啥inf驱动安装成功后会把inf文件换一个名字然后copy到C:\Windows\inf目录下?有高人解答下吗?

DestinationInfFileNameComponent代表copy到C:\Windows\inf目录下的那个inf的名字,这个很有用,调用SetupUninstallOEMInf卸载驱动的时候要用到这个名字。

然后我在C#中这么调用SetupCopyOEMInf:

            unsafe
            {
                success = SetupCopyOEMInf(infPath, "", OemSourceMediaType.SPOST_PATH, OemCopyStyle.SP_COPY_NEWER, out destinationInfFileName, 260,
                                0, out destinationInfFileNameComponent);
            }

260是文件目录的最大长度,查看log,C:\Windows\inf\setupapi.dev.log,可以成功安装,success为true,但是接下来的问题困扰了我好久,destinationInfFileNameComponent和destinationInfFileName始终都没有值,按照https://msdn.microsoft.com/en-us/library/aa376990.aspx上的说话,成功执行后会返回这俩值,destinationInfFileNameComponent是调用SetupUninstallOEMInf卸载驱动的必传参数,没有值就无法卸载了,google了半天没有解决,最后看别人用C++写的SetupCopyOEMInf,destinationInfFileName传的是一个长度为260的TCHAR数组,于是我把C#的SetupCopyOEMInf原型改为:

        [DllImport("setupapi.dll", SetLastError = true)]
        private static extern bool SetupCopyOEMInf(

            string SourceInfFileName,
            string OEMSourceMediaLocation,
            OemSourceMediaType OEMSourceMediaType,
            OemCopyStyle CopyStyle,
            out char[] DestinationInfFileName,
            int DestinationInfFileNameSize,
            int RequiredSize,
            out string DestinationInfFileNameComponent

        );

然后把destinationInfFileName声明为一个260长度的char数组,但是调用会报executionexception的异常。后来把原型参数char[] destinationInfFileName前面的out去掉,destinationInfFileNameComponent的值终于正确得到了!!!!!!!!

但是destinationInfFileName依然无法得到,好歹有了一个,终于可以做卸载了,具体为什么可以了也不太清楚,为什么PTSTR DestinationInfFileName传递C#的string不对?传递char数组才可以,但是无法使用out,估计destinationInfFileNameComponent是在destinationInfFileName的基础上得到的,所以传递string类型的destinationInfFileNameComponent是可以的吧,糊涂了!

完美的解决方法

原型:

        [DllImport("setupapi.dll", SetLastError = true)]
        private static extern bool SetupCopyOEMInf(

            string SourceInfFileName,
            string OEMSourceMediaLocation,
            OemSourceMediaType OEMSourceMediaType,
            OemCopyStyle CopyStyle,
            StringBuilder DestinationInfFileName,
            int DestinationInfFileNameSize,
            int RequiredSize,
            out string DestinationInfFileNameComponent

        );

 

调用:

 string msg = "";
            int size = 0;
            StringBuilder destinationInfFileName_builder = new StringBuilder(260);
            unsafe
            {
                success = SetupCopyOEMInf(infPath, "", OemSourceMediaType.SPOST_PATH, OemCopyStyle.SP_COPY_NEWER, destinationInfFileName_builder, destinationInfFileName_builder.Capacity,
                                0,out destinationInfFileNameComponent);
            }
            if (!success)
            {
                var errorCode = Marshal.GetLastWin32Error();
                var errorString = new Win32Exception(errorCode).Message;
                msg = errorString;
            }

 

 把destinationInfFileName设成一个有260个字符长的空stringbuilder,stringbuilder是按引用传值,所以不需要添加out或者ref了,但是destinationInfFileNameComponent必须是out string,设成stringbuilder会是乱码。

这样destinationInfFileNameComponent和destinationInfFileName都能正确得到了!这样是不是可以猜测,C#调用WINAPI,如果函数原型参数是_Out_opt_  PTSTR,并且这个PTSTR要有长度输入,在C#中就可以声明成StringBuilder?

 

参考:

http://www.pinvoke.net/default.aspx/setupapi.SetupCopyOEMInf

https://msdn.microsoft.com/en-us/library/aa376990.aspx

http://stackoverflow.com/questions/18404660/how-to-use-setupcopyoeminf-during-installer

posted @ 2016-04-28 18:45  mrhyher  阅读(1807)  评论(0编辑  收藏  举报