Working with golang in windows environment

polaris · · 588 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi everyone,</p> <p>We&#39;re looking to deploy our application in windows environment and the problem I faced when compiling and running it as a service on other window machines is the system variables. For example, one of our features needs to access certain files within the C:\User\Username\AppData directory but run into issues where it goes to C:\Windows\System32\config using the os package and running a os.Getenv(&#34;AppData&#34;). Also, I see that running a %USERNAME% doesn&#39;t give back the proper variables once compiled and run. However, if I run the code locally, it does have the correct file/dir. So, I was wondering if you can provide me some understanding or a solution to the problem I&#39;m facing. Thanks</p> <hr/>**评论:**<br/><br/>Sphax: <pre><p>If it&#39;s a proper windows service, it won&#39;t run as your user but rather as administrator. I got burned by this too. As far as I can tell there&#39;s no way to have a service run as a user, but I may well be mistaken here. What I ended up doing was setting my app to be &#34;autorun&#34; via <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa376977(v=vs.85).aspx" rel="nofollow">this registry key</a>. You can look at the function <code>enableAutoRun</code> I wrote <a href="https://git.vrischmann.me/orryg/blob/master/gui_windows.go#L-427" rel="nofollow">here</a>.</p> <p>Also, I would suggest not using environment variables on Windows, the Win32 API provides a way to get what you want, and it&#39;s easily obtainable with Go. For example take a look at what I&#39;ve done <a href="https://github.com/vrischmann/userdir/blob/master/userdir_windows.go" rel="nofollow">here</a> to get the AppData path. To get the username, you would call <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms724432(v=vs.85).aspx" rel="nofollow">this</a> via the same procedure.</p></pre>kgp415: <pre><p>ahh thanks man! I&#39;ve went down the rabbit whole this past week and noticed the lack of understanding I have with the windows environment. I&#39;ll go ahead a take a look into what you provided and start testing things out. Btw, have you run into any issues with any of the window versions when running these scripts( 7,8,10 )?</p></pre>Sphax: <pre><p>I&#39;m running Windows 10 and never tested my app on anything else, so I can&#39;t say for sure, but the APIs I mentioned are super old and standard, so I&#39;d expect it would work on 7 and 8 too.</p></pre>kgp415: <pre><p>Ok, thanks for the head up. Well appreciated</p></pre>globalgobble: <pre><blockquote> <p>this</p> </blockquote> <p>You call that easy ? what is that dancing with syscall and uintptrs ? :-|</p></pre>Sphax: <pre><p>That dancing is necessary to call into the Win32 API without resorting to cgo, which is good because nobody wants to have a C compiler installed to compile some Go code. This really is the easiest way to interact with Windows.</p></pre>globalgobble: <pre><p>Ok but where did you get the stuff from to call syscall.GUID ? I guess the uintptr stuff and so on is mentioned in the definitions for api in MSD. How is it with .NET stuff ? how would you call stuff from System.DirectoryServices.ActiveDirectory ?</p></pre>Sphax: <pre><p><code>SHGetKnownFolderPath</code> takes a pointer to a <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/dd378457(v=vs.85).aspx" rel="nofollow">KNOWNFOLDERID</a>. In reality it&#39;s just a GUID, so for example for <code>FOLDERID_AppsFolder</code> you take the GUID <code>{1e87508d-89c2-42f0-8a7e-645a0f50ca58}</code> and build a <code>syscall.GUID</code> out of that. They have the same structure in memory so it works. As for .NET stuff I have no idea. I&#39;m not sure you can load a .NET dll with Go.</p></pre>globalgobble: <pre><blockquote> <p>1e87508d-89c2-42f0-8a7e-645a0f50ca58</p> </blockquote> <p>How did you build a syscall.GUID out of that ? I can google for &#34;1e87508d-89c2-42f0-8a7e-645a0f50ca58&#34; and I can find: 0x3EB685DB, 0x65F9, 0x4CF6, [8]byte{0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D},</p> <p>but I can&#39;t find out how to convert it.</p></pre>Sphax: <pre><p>Can&#39;t find the doc for syscall.GUID since it&#39;s Windows-only but it follows the same structure as the <a href="https://msdn.microsoft.com/fr-fr/library/windows/desktop/aa373931(v=vs.85).aspx" rel="nofollow">Win32 GUID</a>. The string representation gives you the numbers to use. So for <code>1e87508d-89c2-42f0-8a7e-645a0f50ca58</code> you get <code>syscall.GUID{0x1e87508d, 0x89c2, 0x42f0, []byte{0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}}</code>. </p></pre>globalgobble: <pre><p>Ahhh I get it! Thank you. So in a nutshell if you want to get things like a host&#39;s domainname you can&#39;t because it&#39;s part of the .NET</p></pre>kgp415: <pre><p>So, I tested the script(<a href="https://github.com/vrischmann/userdir/blob/master/userdir_windows.go" rel="nofollow">https://github.com/vrischmann/userdir/blob/master/userdir_windows.go</a>) you provided and here&#39;s what happened. Once I compiled the code to search for the user data directory, I ran it as a service using nssm(service manager), checked the logs, and still returned the C:\Windows\system32\config\systemprofile\AppData\Roaming folder. Any suggestions? Thanks</p></pre>Sphax: <pre><p>Yeah, like I said this is expected for a service. At least from my research you can&#39;t run a service as a &#34;normal&#34; user.</p></pre>intermernet: <pre><p>Windows services can be run as any user by either changing the &#34;RunAs&#34; tab in the services GUI, or modifying / creating the service config with the &#34;sc&#34; utility.</p> <p>This does have a few caveats to do with permissions, but similar issues exist with all operating systems.</p> <p>There is also the golang.org/x/sys/windows package which may help with some of the username stuff (I think it basically does the same syscall dance that you&#39;re doing, but it&#39;s maintained by the Go team so it may be a safer option in the long run.</p></pre>Sphax: <pre><p>Thanks for letting me know about RunAs, I&#39;ll have to look into that. As for <code>golang.org/x/sys/windows</code> I totally agree, if it has what you want you should use it, but in this case it doesn&#39;t wrap <code>SHGetKnownFolderPath</code>.</p></pre>that_how_it_be: <pre><p>I try to avoid environment variables for configurable options for my programs. I prefer config files or command line options as they are less obscure when looking at stuff later or migrating to a new machine.</p> <p>By default I like my programs to have a <em>home</em> directory that they run out of with whatever they need in it. By default I have them pick up the directory of the executable but usually I allow it to be overridden with a -h command line option.</p> <p>You <em>can</em> specify a Windows service to run as a particular user but I would only do that for locking down permissions and not for the location of resources.</p></pre>kardianos: <pre><p>I recommend you use something like</p> <p>github.com/kardianos/service</p> <p>Then get a directory where the exec is running with github.com/kardianos/osext for your config file.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

588 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传